Skip to content

Instantly share code, notes, and snippets.

@syzdek syzdek/locky-dga.c
Last active Feb 25, 2016

Embed
What would you like to do?
Locky Ransomware Domain Generation Algorithm
/*
* 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
You can’t perform that action at this time.