Last active
February 25, 2016 07:24
Locky Ransomware Domain Generation Algorithm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Locky Ransomware Domain Generation Algorithm | |
* | |
* Original code from Forcepoint Security Labs: | |
* https://blogs.forcepoint.com/security-labs/locky-ransomware-encrypts-documents-databases-code-bitcoin-wallets-and-more | |
* | |
* Code updated by David M. Syzdek <ten . kedzys @ divad> on 2016/02/24 | |
* | |
* Compile with: | |
* gcc -W -Wall -Werror -o locky-dga locky-dga.c | |
*/ | |
/////////////// | |
// // | |
// Headers // | |
// // | |
/////////////// | |
#define _XOPEN_SOURCE | |
#include <stdio.h> | |
#include <time.h> | |
#include <inttypes.h> | |
#include <stdlib.h> | |
#include <strings.h> | |
#include <string.h> | |
////////////////// | |
// // | |
// Prototypes // | |
// // | |
////////////////// | |
uint32_t rotl32(uint32_t x, uint32_t n); | |
uint32_t rotr32(uint32_t x, uint32_t n); | |
char * lockydga(unsigned int seed, struct tm * st); | |
int main(int argc, char *argv[]); | |
///////////////// | |
// // | |
// Functions // | |
// // | |
///////////////// | |
uint32_t rotl32(uint32_t x, uint32_t n) | |
{ | |
n = n % 32; | |
return (x<<n) | (x>>(-n&31)); | |
} | |
uint32_t rotr32(uint32_t x, uint32_t n) | |
{ | |
n = n % 32; | |
return (x>>n) | (x<<(-n&31)); | |
} | |
char * lockydga(unsigned int seed, struct tm * st) | |
{ | |
int32_t modConst1 = 0xB11924E1; | |
int32_t modConst2 = 0x27100001; | |
int32_t modConst3 = 0x2709A354; | |
int32_t modYear; | |
int32_t modMonth; | |
int32_t modDay; | |
int32_t modBase = 0; | |
int32_t i = 0i; | |
int32_t genLength = 0; | |
uint32_t x = 0; | |
uint32_t y = 0; | |
uint32_t z = 0; | |
uint32_t modFinal = 0; | |
char * domain; | |
char tldchars[29] = "rupweuinytpmusfrdeitbeuknltf"; | |
// Perform some shifts with the constants | |
modYear = rotr32(modConst1 * (st->tm_year + 0x1BF5 + 1900), 5); | |
modDay = rotr32(modConst1 * (modYear + (st->tm_mday >> 1) + modConst2), 5); | |
modMonth = rotr32(modConst1 * (modDay + st->tm_mon + modConst3 + 1), 5); | |
modBase = rotl32(seed % 6, 21); | |
modFinal = rotr32(modConst1 * (modMonth + modBase + modConst2), 5); | |
modFinal += 0x27100001; | |
// Length without TLD | |
genLength = modFinal % 11 + 5; | |
if (genLength == 0) | |
return(NULL); | |
// Allocate full length including TLD and null terminator | |
if ((domain = (char *)malloc(modFinal % 11 + 8 + 1)) == NULL) | |
{ | |
perror("malloc()"); | |
return(NULL); | |
}; | |
// Generate domain string before TLD | |
do | |
{ | |
x = rotl32(modFinal, i); | |
y = rotr32(modConst1 * x, 5); | |
z = y + modConst2; | |
modFinal = z; | |
domain[i++] = z % 25 + 97; | |
} | |
while (i < genLength); | |
// Add a '.' before the TLD | |
domain[i] = '.'; | |
// Generate the TLD from a hard-coded key-string of characters | |
x = rotr32(modConst1 * modFinal, 5); | |
y = (x + modConst2) % ( (sizeof(tldchars) - 1) / 2 ); | |
domain[i + 1] = tldchars[2 * y]; | |
domain[i + 2] = tldchars[2 * y + 1]; | |
domain[i + 3] = 0; // Null-terminate | |
return domain; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
time_t epoch; | |
struct tm st; | |
void * ptr; | |
char * domain; | |
uint32_t count; | |
int fmt; | |
fmt = 0; | |
if ((argc < 2) || (argc > 3)) | |
{ | |
fprintf(stderr, "Usage: %s [ <YYYYMMDD> | <YYYY-MM-DD> | <epoch> | NOW ] [ csv | list ]\n", argv[0]); | |
return(1); | |
}; | |
if (argc == 3) | |
{ | |
if (!(strcasecmp(argv[2], "csv"))) | |
fmt = 1; | |
else if (!(strcasecmp(argv[2], "list"))) | |
fmt = 0; | |
else | |
{ | |
fprintf(stderr, ": unknown data format\n"); | |
return(1); | |
}; | |
}; | |
if (!(strcasecmp(argv[1], "NOW"))) | |
{ | |
epoch = time(NULL); | |
if ((ptr = localtime_r(&epoch, &st)) == NULL) | |
{ | |
perror("localtime_r()"); | |
return(1); | |
}; | |
} | |
else | |
{ | |
ptr = strptime(argv[1], "%Y-%m-%d", &st); | |
if (ptr == NULL) | |
if (strlen(argv[1]) > 8) | |
ptr = strptime(argv[1], "%s", &st); | |
if (ptr == NULL) | |
ptr = strptime(argv[1], "%Y%m%d", &st); | |
if (ptr == NULL) | |
{ | |
perror("strptime()"); | |
return(1); | |
}; | |
}; | |
printf( | |
((fmt == 0) ? "Domains for %04i-%02i-%02i:" : "%04i-%02i-%02i,"), | |
(st.tm_year + 1900), | |
(st.tm_mon + 1), | |
st.tm_mday | |
); | |
for (count = 0; count < 6; count++) | |
{ | |
if ((domain = lockydga(count, &st)) != NULL) | |
{ | |
printf(((fmt == 0) ? "\n %s" : "%s,"), domain); | |
free(domain); | |
}; | |
}; | |
printf("\n"); | |
return(0); | |
} | |
/* end of source */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment