Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- dcanalyzer.c
- --
- Analyzer for DarkComet Servers, make sure the server is fully unpacked before
- using this tool. It will decrypt all known data, if it doesn't work you may be
- working with a very old version of darkcomet and you should have a look at
- the PE resources for the unencrypted data.
- This tool is public domain. Tested under GCC and VS2010 with many darkcomet
- versions.
- */
- #define _BSD_SOURCE /* make gcc happy with snprintf as ansi */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <string.h>
- #ifdef WIN32
- #include <Windows.h>
- #endif
- #if _MSC_VER
- #define snprintf _snprintf /* work around for microsoft's "C" compiler */
- #endif
- /* We search the entire file for this string to find the RC4 key */
- #define KEY_PREFIX "#KCMDDC"
- int process(char * file);
- void ShowOutput(char * str);
- void process_resource_table(int pos, char found, char * goal);
- FILE * fh;
- int32_t rsrc_pos;
- int32_t rsrc_virtual;
- char * dcstr = NULL;
- /* RC4 borrowed from FreeBSD */
- struct rc4_state {
- uint8_t perm[256];
- uint8_t index1;
- uint8_t index2;
- };
- static __inline void swap_bytes(uint8_t *a, uint8_t *b)
- {
- uint8_t temp;
- temp = *a;
- *a = *b;
- *b = temp;
- }
- void rc4_init(struct rc4_state * state, uint8_t *key, int keylen)
- {
- uint8_t j;
- int i;
- /* Initialize state with identity permutation */
- for (i = 0; i < 256; i++)
- state->perm[i] = (uint8_t)i;
- state->index1 = 0;
- state->index2 = 0;
- /* Randomize the permutation using key data */
- for (j = i = 0; i < 256; i++) {
- j += state->perm[i] + key[i % keylen];
- swap_bytes(&state->perm[i], &state->perm[j]);
- }
- }
- void rc4_crypt(struct rc4_state * state, uint8_t *inbuf, uint8_t *outbuf,
- int buflen)
- {
- int i;
- uint8_t j;
- for (i = 0; i < buflen; i++) {
- /* Update modification indicies */
- state->index1++;
- state->index2 += state->perm[state->index1];
- /* Modify permutation */
- swap_bytes(&state->perm[state->index1],
- &state->perm[state->index2]);
- /* Encrypt/decrypt next byte */
- j = state->perm[state->index1] + state->perm[state->index2];
- outbuf[i] = inbuf[i] ^ state->perm[j];
- }
- }
- /* end FreeBSD RC4 code */
- /* my PE header structs */
- struct DATA_DIR
- {
- uint32_t addr;
- uint32_t size;
- };
- struct RES_DIR_TABLE
- {
- uint32_t characteristics;
- uint32_t timestamp;
- uint16_t major;
- uint16_t minor;
- uint16_t num_name_elems;
- uint16_t num_id_elems;
- };
- struct RES_DIR_ENTRY
- {
- union
- {
- uint32_t name_rva;
- uint32_t id;
- } identifier;
- union
- {
- uint32_t data_entry_rva;
- uint32_t subdir_rva;
- } child;
- };
- struct RES_DATA
- {
- uint32_t data_rva;
- uint32_t size;
- uint32_t codepage;
- uint32_t reserved;
- };
- void process_resource_entry(struct RES_DIR_ENTRY entry, char found,
- char * goal)
- {
- struct RES_DATA data;
- if (entry.child.data_entry_rva & 0x80000000) {
- /* process subdir entry */
- process_resource_table(entry.child.subdir_rva & 0x7FFFFFFF,
- found, goal);
- } else {
- if (found) {
- fseek(fh, rsrc_pos + entry.child.data_entry_rva,
- SEEK_SET);
- fread(&data, sizeof(data), 1, fh);
- dcstr = (char*) malloc(data.size+1);
- dcstr[data.size] = '\0';
- fseek(fh, data.data_rva - rsrc_virtual + rsrc_pos,
- SEEK_SET);
- fread(dcstr, 1, data.size, fh);
- }
- /* process data entry */
- }
- }
- void process_resource_entry_id(struct RES_DIR_ENTRY entry, char found,
- char * goal)
- {
- process_resource_entry(entry, found, goal);
- }
- char check_unicode_str(char * goal, char * input, unsigned int len)
- {
- unsigned int i;
- char next;
- if (strlen(goal) == len) {
- for (i = 0; i < len*2; i++) {
- next = (i % 2) == 0 ? goal[i/2] : 0;
- if (input[i] != next)
- return 0;
- }
- } else {
- return 0;
- }
- return 1;
- }
- void process_resource_entry_name(struct RES_DIR_ENTRY entry, char found,
- char * goal)
- {
- uint16_t name_len;
- char * name;
- fseek(fh, rsrc_pos + (entry.identifier.name_rva & 0x7FFFFFFF), SEEK_SET);
- fread(&name_len, sizeof(name_len), 1, fh);
- name = (char*) malloc(name_len*2 + 1);
- fread(name, 1, name_len*2, fh);
- if (check_unicode_str(goal, name, name_len)) {
- process_resource_entry(entry, 1, goal);
- } else {
- process_resource_entry(entry, found, goal);
- }
- }
- void process_resource_table(int pos, char found, char * goal)
- {
- struct RES_DIR_TABLE table;
- int i;
- int length;
- struct RES_DIR_ENTRY * entries;
- fseek(fh, rsrc_pos + pos, SEEK_SET);
- fread(&table, sizeof(table), 1, fh);
- length = sizeof(struct RES_DIR_ENTRY) *
- (table.num_id_elems + table.num_name_elems);
- entries = (struct RES_DIR_ENTRY*) malloc(length);
- fread(entries, length, 1, fh);
- for (i = 0; i < table.num_name_elems; i++) {
- process_resource_entry_name(entries[i], found, goal);
- }
- for (i = 0; i < table.num_id_elems; i++) {
- process_resource_entry_id(entries[i], found, goal);
- }
- }
- char * decrypt_dcdata(char * instr, char * key)
- {
- struct rc4_state rc4state;
- int i;
- int len = strlen(instr)/2;
- char * data;
- unsigned int tempdata;
- data = (char *)malloc(len);
- for (i = 0; i < len; i++) {
- sscanf(instr+(i*2), "%2X", &tempdata);
- data[i] = (char) tempdata;
- }
- rc4_init(&rc4state, (uint8_t*)key, strlen(key));
- rc4_crypt(&rc4state, (uint8_t*)data, (uint8_t*)data, len);
- data[len] = '\0';
- return data;
- }
- int main(int argc, char** argv) {
- if (argc < 2) {
- ShowOutput("Please specify a file!");
- return EXIT_FAILURE;
- }
- return process(argv[1]);
- }
- #ifdef WIN32
- int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
- LPSTR lpCmdLine, int nCmdShow)
- {
- char buffer[8192];
- OPENFILENAME ofn;
- if (__argc > 1) {
- return main(__argc, __argv);
- } else {
- ZeroMemory( &ofn , sizeof( ofn));
- ofn.lStructSize = sizeof(ofn);
- ofn.lpstrFile = buffer;
- ofn.lpstrFile[0] = '\0';
- ofn.nMaxFile = sizeof(buffer);
- ofn.lpstrFilter = "DarkComet Server Executables\0*.exe";
- ofn.nFilterIndex = 1;
- ofn.lpstrFileTitle = NULL;
- ofn.nMaxFileTitle = 0;
- ofn.lpstrInitialDir = NULL;
- ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
- GetOpenFileName(&ofn);
- return process(ofn.lpstrFile);
- }
- }
- #endif
- void ShowOutput(char * str)
- {
- #ifdef WIN32
- MessageBoxExA(NULL, str, "DCAnalyzer", 0, 0);
- #else
- printf("%s\n", str);
- #endif
- }
- /* simple scanner to parse key out of executable */
- char * find_key_by_force()
- {
- int pos = 0;
- char * prefix = KEY_PREFIX;
- int max = strlen(prefix);
- char * keybuf = (char*) malloc(4096);
- char cur;
- fseek(fh, 0, SEEK_SET); /* go to start of file */
- do {
- fread(&cur, 1, 1, fh);
- if (pos >= max) {
- keybuf[pos] = cur;
- if (cur == '\0')
- break;
- pos++;
- } else if (cur == prefix[pos]) {
- keybuf[pos] = cur;
- pos++;
- } else {
- pos = 0;
- }
- if (pos == 4096) /* no heap overflow for you! */
- break;
- } while (!feof(fh));
- strncat(keybuf, "890", 4096); /* comes from a separate function */
- return keybuf;
- }
- int process(char * file)
- {
- uint16_t mz_hdr;
- uint32_t pe_hdr_loc;
- uint32_t pe_hdr;
- uint16_t opt_hdr;
- uint32_t num_rva_sizes;
- uint32_t image_base;
- unsigned int opt_hdr_pos;
- unsigned int i;
- char * output;
- char buffer[1024];
- char final_buffer[8192];
- char section_name[9];
- char found;
- int successful;
- char * key;
- /* We search for these when we can't find the new DCDATA resource.
- Used for old versions of DarkComet */
- char * fallbacks[] = {"FWB", "GENCODE", "MUTEX", "NETDATA", "OFFLINEK",
- "SID", "FTPUPLOADK", "FTPHOST", "FTPUSER", "FTPPASS", "FTPPORT",
- "FTPSIZE", "FTPROOT", "PWD"};
- fh = fopen(file, "rb");
- if (fh == NULL) {
- ShowOutput("File open failed");
- return EXIT_FAILURE;
- }
- key = find_key_by_force();
- fseek(fh, 0, SEEK_SET); /* go to start of file */
- section_name[8] = '\0';
- fread(&mz_hdr, sizeof(int16_t), 1, fh); /* read first 2 bytes of file */
- if (mz_hdr != *(uint16_t*)"MZ") {
- ShowOutput("Not an MZ Executable!");
- return EXIT_FAILURE;
- }
- fseek(fh, 0x3C, SEEK_SET);
- fread(&pe_hdr_loc, sizeof(pe_hdr_loc), 1, fh); /* offset of PE header */
- fseek(fh, pe_hdr_loc, SEEK_SET);
- fread(&pe_hdr, sizeof(pe_hdr), 1, fh);
- if (pe_hdr != *(uint32_t*)"PE\0\0") {
- ShowOutput("Not a PE Executable!");
- return EXIT_FAILURE;
- }
- opt_hdr_pos = pe_hdr_loc + 0x18;
- fseek(fh, opt_hdr_pos, SEEK_SET);
- fread(&opt_hdr, sizeof(opt_hdr), 1, fh);
- if (opt_hdr != 0x010B) {
- ShowOutput("Invalid optional header!");
- return EXIT_FAILURE;
- }
- fseek(fh, opt_hdr_pos + 28, SEEK_SET); /* ImageBase so we can subtract it later */
- fread(&image_base, sizeof(image_base), 1, fh);
- fseek(fh, opt_hdr_pos + 92, SEEK_SET); /* NumberOfRvaAndSizes */
- fread(&num_rva_sizes, sizeof(num_rva_sizes), 1, fh);
- if (num_rva_sizes > 0x10)
- num_rva_sizes = 0x10; /* enforce this so dumb tricks cannot work */
- fseek(fh, num_rva_sizes*8, SEEK_CUR);
- /* we should now be at the section headers */
- found = 0;
- do {
- fread(section_name, 1, 8, fh);
- if (strncmp(".rsrc", section_name, 8) == 0) {
- fseek(fh, 4, SEEK_CUR);
- fread(&rsrc_virtual, 4, 1, fh);
- fseek(fh, 4, SEEK_CUR);
- fread(&rsrc_pos, 4, 1, fh);
- found++;
- fseek(fh, 16, SEEK_CUR); /* skip rest of this section header. */
- } else {
- fseek(fh, 40-8, SEEK_CUR); /* skip rest of this section header. */
- }
- } while (found != 1);
- process_resource_table(0,0, "DCDATA");
- if (dcstr != NULL) {
- ShowOutput(decrypt_dcdata(dcstr, key));
- } else {
- final_buffer[0] = '\0';
- successful = 0;
- for (i = 0; i < (sizeof(fallbacks)/sizeof(*fallbacks)); i++) {
- process_resource_table(0,0, fallbacks[i]);
- if (dcstr != NULL) {
- output = decrypt_dcdata(dcstr, key);
- if (final_buffer[0] == '\0')
- snprintf(buffer, 1024, "%s: %s", fallbacks[i], output);
- else
- snprintf(buffer, 1024, "\n%s: %s", fallbacks[i], output);
- strncat(final_buffer, buffer, 8192);
- successful++;
- dcstr = NULL; /* null it every round */
- }
- }
- if (successful)
- ShowOutput(final_buffer);
- else
- ShowOutput("Could not find any DarkComet resource!\n");
- }
- return EXIT_SUCCESS;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement