/* Copyright 2007 Luigi Auriemma This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA http://www.gnu.org/licenses/gpl.txt */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <sys/stat.h> #include <ctype.h> #include "pe.h" #define VER "0.1" #define round(n) (((n + (PE_align - 1)) / PE_align) * PE_align) void halflife_dll_decrypt(uint8_t *data, uint32_t datasz); void find_impexp_tables(uint8_t *base, uint32_t baseoff, uint32_t *impoff, uint32_t *impsz, uint32_t *expoff, uint32_t *expsz); void dump_section(FILE *fd, uint32_t num, uint8_t *data, uint32_t datasz); uint8_t *fd_read(uint8_t *name, int *fdlen); void fd_write(uint8_t *name, uint8_t *data, int datasz); void std_err(void); int dump = 0; uint8_t *in_file, *out_file; int main(int argc, char *argv[]) { uint32_t filelen; int i; uint8_t *filebuff; fputs("\n" "Half-life DLL decrypter and rebuilder "VER"\n" "by Luigi Auriemma\n" "e-mail: aluigi@autistici.org\n" "web: aluigi.org\n" "\n", stdout); if(argc < 3) { printf("\n" "Usage: %s [options] <input.DLL> <output.DLL>\n" "\n" "Options:\n" "-d dump all the sections of the DLL instead of building the PE file,\n" " use <output.DLL> as base for the sequential output filename\n" "\n", argv[0]); exit(1); } argc -= 2; for(i = 1; i < argc; i++) { if(((argv[i][0] != '-') && (argv[i][0] != '/')) || (strlen(argv[i]) != 2)) { printf("\nError: recheck your options (%s is not valid)\n", argv[i]); exit(1); } switch(argv[i][1]) { case 'd': dump = 1; break; default: { printf("\nError: wrong command-line argument (%s)\n\n", argv[i]); exit(1); } break; } } in_file = argv[argc]; out_file = argv[argc + 1]; filebuff = fd_read(in_file, &filelen); halflife_dll_decrypt(filebuff, filelen); printf("\n- the DLL has been decrypted and %s\n", dump ? "dumped in the various section files" : "rebuilt"); free(filebuff); return(0); } void halflife_dll_decrypt(uint8_t *data, uint32_t datasz) { typedef struct { uint32_t Characteristics; uint32_t Sections; uint32_t copywhat; uint32_t ImageBase; uint32_t EntryPoint; uint32_t ImportTable; } hlhdr_t; typedef struct { uint32_t rva; uint32_t raw_size; uint32_t virtual_size; uint32_t file_offset; uint32_t zero; } hlsec_t; const static char *sec_names[4] = { ".text", ".rdata", ".data", ".rsrc" }; hlhdr_t *hlhdr; hlsec_t *hlsec; FILE *fd; uint32_t i, fdoff, peoff; uint8_t chr, *base; if(*(uint32_t *)(data + 64) != 0x12345678) { printf("\nAlert: this DLL doesn't seem encrypted with the Valve algorithm\n"); } base = data; data += 68; datasz -= 68; chr = 'W'; for(i = 0; i < datasz; i++) { data[i] ^= chr; chr += data[i] + 'W'; } hlhdr = (void *)data; hlsec = (void *)(data + sizeof(hlhdr_t)); hlhdr->copywhat ^= 0x7a32bc85; hlhdr->ImageBase ^= 0x49c042d1; hlhdr->ImportTable ^= 0x872c3d47; hlhdr->EntryPoint -= 12; printf("\n" " Characteristics %08x\n" " Sections %08x\n" " copywhat %08x\n" " ImageBase %08x\n" " EntryPoint %08x\n" " ImportTable %08x\n", hlhdr->Characteristics, hlhdr->Sections, hlhdr->copywhat, hlhdr->ImageBase, hlhdr->EntryPoint, hlhdr->ImportTable); for(i = 0; i <= hlhdr->Sections; i++) { printf("\n" "- section %u\n" " raw_size %08x\n" " virtual_size %08x\n" " file_offset %08x\n" " rva %08x\n" " zero %08x\n", i, hlsec[i].raw_size, hlsec[i].virtual_size, hlsec[i].file_offset, hlsec[i].rva, hlsec[i].zero); if(dump) { dump_section(NULL, i, base + hlsec[i].file_offset, hlsec[i].virtual_size); } } if(dump) return; printf("\n"); /* when all the section have been placed in memory */ /* HL.EXE calls hlhdr->EntryPoint and then hlhdr->copywhat */ /* copying a zone of the DLL in the HL.EXE process */ /* IMPORTANT NOTE */ /* all the PE stuff here and in pe.h seems to work fine */ /* but for the moment I consider it only a work-around */ /* so don't take it too seriously */ for(i = 0; i <= hlhdr->Sections; i++) { PE_size_image += round(hlsec[i].raw_size); } PE_sections = hlhdr->Sections + 1; PE_size_code = hlsec[0].raw_size; PE_entry_point = hlhdr->EntryPoint - hlhdr->ImageBase; PE_base_code = hlsec[0].rva - hlhdr->ImageBase; PE_image_base = hlhdr->ImageBase; PE_Characteristics = hlhdr->Characteristics; printf("- search offsets and sizes of the import and export tables\n"); PE_import_rva = hlhdr->ImportTable; find_impexp_tables( base + hlsec[1].file_offset, hlsec[1].rva, &PE_import_rva, &PE_import_size, &PE_export_rva, &PE_export_size); PE_import_rva -= PE_image_base; PE_export_rva -= PE_image_base; if(hlhdr->Sections >= 3) { PE_resource_rva = hlsec[3].rva - PE_image_base; PE_resource_size = hlsec[3].virtual_size; } printf("- now I try to build the PE DLL (experimental)\n\n"); fd = fopen(out_file, "wb"); if(!fd) std_err(); PE_dos_fwrite(fd); PE_sign_fwrite(fd); PE_file_fwrite(fd); PE_optional_fwrite(fd); peoff = ftell(fd); fseek(fd, PE_base_code, SEEK_SET); for(i = 0; i <= hlhdr->Sections; i++) { fdoff = ftell(fd); printf(" section %u -> %08x -> %08x\n", i, (uint32_t)ftell(fd), hlsec[i].rva); dump_section(fd, i, base + hlsec[i].file_offset, hlsec[i].virtual_size); hlsec[i].file_offset = fdoff; // here file_offset becomes our new offset } fseek(fd, peoff, SEEK_SET); for(i = 0; i <= hlhdr->Sections; i++) { PE_Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE; PE_virtual_size = hlsec[i].virtual_size; PE_rva = hlsec[i].rva; PE_raw_size = hlsec[i].raw_size; PE_file_offset = hlsec[i].file_offset; if(i < 4) { strcpy(PE_section_name, sec_names[i]); } else { sprintf(PE_section_name, "sec%u", i); } PE_section_fwrite(fd); } fclose(fd); } /* the following stupid function takes the data where starts the import table */ /* and finds its size and the offset and size of the export table too */ void find_impexp_tables(uint8_t *base, uint32_t baseoff, uint32_t *impoff, uint32_t *impsz, uint32_t *expoff, uint32_t *expsz) { uint32_t off, maxoff; uint16_t hint; uint8_t *data, *p; data = base + (*impoff - baseoff); p = data; maxoff = 0; while((off = *(uint32_t *)(p + 12))) { if(off > maxoff) maxoff = off; p += 20; } maxoff -= (baseoff - PE_image_base); p = base + maxoff; while(*p++); if((p - base) & 1) p++; while((hint = *(uint16_t *)p)) { p += 2; while(*p++); if((p - base) & 1) p++; } while(!*p) p++; // blah I think it's lame p -= ((p - base) & 3); p -= 4; *impsz = p - data; *expoff = (p - base) + baseoff; data = p; off = *(uint32_t *)(p + 12); off -= (baseoff - PE_image_base); p = base + off; while(*p) { while(*p++); } if((p - base) & 1) p++; *expsz = p - data; printf("- import table found: %08x -> %u\n", *impoff - baseoff, *impsz); printf("- export table found: %08x -> %u\n", *expoff - baseoff, *expsz); } void dump_section(FILE *fd, uint32_t num, uint8_t *data, uint32_t datasz) { uint32_t i, zero; uint8_t *fname = NULL, *p; if(dump) { fname = malloc(strlen(out_file) + 12); p = strrchr(out_file, '.'); if(p) { sprintf(fname, "%.*s_%u.%s", p - out_file, out_file, num, p + 1); } else { sprintf(fname, "%s_%u.dll", out_file, num); } printf("- write %s\n", fname); fd = fopen(fname, "wb"); if(!fd) std_err(); } fwrite(data, datasz, 1, fd); if(dump) { fclose(fd); free(fname); } else { zero = round(datasz); for(i = datasz; i < zero; i++) { fputc(0, fd); } } } uint8_t *fd_read(uint8_t *name, int *fdlen) { struct stat xstat; FILE *fd; uint8_t *buff; printf("- open file %s\n", name); fd = fopen(name, "rb"); if(!fd) std_err(); fstat(fileno(fd), &xstat); buff = malloc(xstat.st_size); fread(buff, xstat.st_size, 1, fd); fclose(fd); *fdlen = xstat.st_size; return(buff); } void fd_write(uint8_t *name, uint8_t *data, int datasz) { FILE *fd; printf("- create file %s\n", name); fd = fopen(name, "rb"); if(fd) { fclose(fd); printf("- file already exists, do you want to overwrite it (y/N)?\n "); fflush(stdin); if(tolower(fgetc(stdin)) != 'y') exit(1); } fd = fopen(name, "wb"); if(!fd) std_err(); fwrite(data, datasz, 1, fd); fclose(fd); } void std_err(void) { perror("\nError"); exit(1); }
/* Copyright 2007 Luigi Auriemma This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA http://www.gnu.org/licenses/gpl.txt */ #include <stdio.h> #include <stdlib.h> #include <cstdint.h> #include <string.h> /* DEFINES */ #define IMAGE_DOS_SIGNATURE 0x5A4D #define IMAGE_OS2_SIGNATURE 0x454E #define IMAGE_OS2_SIGNATURE_LE 0x454C #define IMAGE_VXD_SIGNATURE 0x454C #define IMAGE_NT_SIGNATURE 0x00004550 #define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b #define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b #define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC #define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 #define IMAGE_SEPARATE_DEBUG_SIGNATURE 0x4944 #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 #define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 #define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 #define IMAGE_SIZEOF_NT_OPTIONAL_HEADER 224 #define IMAGE_SIZEOF_SHORT_NAME 8 #define IMAGE_SIZEOF_SECTION_HEADER 40 #define IMAGE_SIZEOF_SYMBOL 18 #define IMAGE_SIZEOF_AUX_SYMBOL 18 #define IMAGE_SIZEOF_RELOCATION 10 #define IMAGE_SIZEOF_BASE_RELOCATION 8 #define IMAGE_SIZEOF_LINENUMBER 6 #define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 #define IMAGE_FILE_MACHINE_I386 0x014c #define IMAGE_FILE_RELOCS_STRIPPED 1 #define IMAGE_FILE_EXECUTABLE_IMAGE 2 #define IMAGE_FILE_LINE_NUMS_STRIPPED 4 #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 8 #define IMAGE_FILE_AGGRESIVE_WS_TRIM 16 #define IMAGE_FILE_LARGE_ADDRESS_AWARE 32 #define IMAGE_FILE_BYTES_REVERSED_LO 128 #define IMAGE_FILE_32BIT_MACHINE 256 #define IMAGE_FILE_DEBUG_STRIPPED 512 #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 1024 #define IMAGE_FILE_NET_RUN_FROM_SWAP 2048 #define IMAGE_FILE_SYSTEM 4096 #define IMAGE_FILE_DLL 8192 #define IMAGE_FILE_UP_SYSTEM_ONLY 16384 #define IMAGE_FILE_BYTES_REVERSED_HI 32768 #define IMAGE_SUBSYSTEM_UNKNOWN 0 #define IMAGE_SUBSYSTEM_NATIVE 1 #define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 #define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 #define IMAGE_SUBSYSTEM_OS2_CUI 5 #define IMAGE_SUBSYSTEM_POSIX_CUI 7 #define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 #define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 #define IMAGE_SUBSYSTEM_XBOX 14 #define IMAGE_SCN_CNT_CODE 32 #define IMAGE_SCN_CNT_INITIALIZED_DATA 64 #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 128 #define IMAGE_SCN_LNK_OTHER 256 #define IMAGE_SCN_LNK_INFO 512 #define IMAGE_SCN_TYPE_OVER 1024 #define IMAGE_SCN_LNK_REMOVE 2048 #define IMAGE_SCN_LNK_COMDAT 4096 #define IMAGE_SCN_MEM_DISCARDABLE 0x2000000 #define IMAGE_SCN_MEM_NOT_CACHED 0x4000000 #define IMAGE_SCN_MEM_NOT_PAGED 0x8000000 #define IMAGE_SCN_MEM_SHARED 0x10000000 #define IMAGE_SCN_MEM_EXECUTE 0x20000000 #define IMAGE_SCN_MEM_READ 0x40000000 #define IMAGE_SCN_MEM_WRITE 0x80000000 /* STRUCTURES */ typedef struct { uint16_t e_magic; uint16_t e_cblp; uint16_t e_cp; uint16_t e_crlc; uint16_t e_cparhdr; uint16_t e_minalloc; uint16_t e_maxalloc; uint16_t e_ss; uint16_t e_sp; uint16_t e_csum; uint16_t e_ip; uint16_t e_cs; uint16_t e_lfarlc; uint16_t e_ovno; uint16_t e_res[4]; uint16_t e_oemid; uint16_t e_oeminfo; uint16_t e_res2[10]; int32_t e_lfanew; } IMAGE_DOS; typedef struct { uint16_t Machine; uint16_t NumberOfSections; uint32_t TimeDateStamp; uint32_t PointerToSymbolTable; uint32_t NumberOfSymbols; uint16_t SizeOfOptionalHeader; uint16_t Characteristics; } IMAGE_FILE; typedef struct { uint32_t VirtualAddress; uint32_t Size; } IMAGE_DATA_DIRECTORY; typedef struct { uint16_t Magic; uint8_t MajorLinkerVersion; uint8_t MinorLinkerVersion; uint32_t SizeOfCode; uint32_t SizeOfInitializedData; uint32_t SizeOfUninitializedData; uint32_t AddressOfEntryPoint; uint32_t BaseOfCode; uint32_t BaseOfData; uint32_t ImageBase; uint32_t SectionAlignment; uint32_t FileAlignment; uint16_t MajorOperatingSystemVersion; uint16_t MinorOperatingSystemVersion; uint16_t MajorImageVersion; uint16_t MinorImageVersion; uint16_t MajorSubsystemVersion; uint16_t MinorSubsystemVersion; uint32_t Win32VersionValue; uint32_t SizeOfImage; uint32_t SizeOfHeaders; uint32_t CheckSum; uint16_t Subsystem; uint16_t DllCharacteristics; uint32_t SizeOfStackReserve; uint32_t SizeOfStackCommit; uint32_t SizeOfHeapReserve; uint32_t SizeOfHeapCommit; uint32_t LoaderFlags; uint32_t NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL32; #define PE_DIR_ExportTable DataDirectory[0] #define PE_DIR_ImportTable DataDirectory[1] #define PE_DIR_Resource DataDirectory[2] #define PE_DIR_Exception DataDirectory[3] #define PE_DIR_Security DataDirectory[4] #define PE_DIR_Relocation DataDirectory[5] #define PE_DIR_Debug DataDirectory[6] #define PE_DIR_Copyright DataDirectory[7] #define PE_DIR_GlobalPtr DataDirectory[8] #define PE_DIR_TLSTable DataDirectory[9] #define PE_DIR_LoadConfig DataDirectory[10] #define PE_DIR_BoundImport DataDirectory[11] #define PE_DIR_IAT DataDirectory[12] #define PE_DIR_DelayImport DataDirectory[13] #define PE_DIR_COM DataDirectory[14] #define PE_DIR_Reserved DataDirectory[15] typedef struct { uint8_t Name[IMAGE_SIZEOF_SHORT_NAME]; union { uint32_t PhysicalAddress; uint32_t VirtualSize; } Misc; uint32_t VirtualAddress; uint32_t SizeOfRawData; uint32_t PointerToRawData; uint32_t PointerToRelocations; uint32_t PointerToLinenumbers; uint16_t NumberOfRelocations; uint16_t NumberOfLinenumbers; uint32_t Characteristics; } IMAGE_SECTION_HEADER; /* GLOBAL VARIABLES */ uint32_t PE_align = 0x1000, PE_sections = 0, PE_size_code = 0, PE_entry_point = 0, PE_base_code = 0x00001000, PE_image_base = 0, PE_size_image = 0, PE_Characteristics = 0, PE_virtual_size = 0, PE_file_offset = 0, PE_raw_size = 0, PE_rva = 0, PE_export_rva = 0, PE_export_size = 0, PE_import_rva = 0, PE_import_size = 0, PE_iat_rva = 0, PE_iat_size = 0, PE_resource_rva = 0, PE_resource_size = 0; uint8_t PE_section_name[IMAGE_SIZEOF_SHORT_NAME]; /* FUNCTIONS */ void PE_dos_fwrite(FILE *fd) { IMAGE_DOS hdr; const static uint8_t dosdata[64] = "\x0E\x1F\xBA\x0E\x00\xB4\x09\xCD\x21\xB8\x01\x4C\xCD\x21\x54\x68" "\x69\x73\x20\x70\x72\x6F\x67\x72\x61\x6D\x20\x63\x61\x6E\x6E\x6F" "\x74\x20\x62\x65\x20\x72\x75\x6E\x20\x69\x6E\x20\x44\x4F\x53\x20" "\x6D\x6F\x64\x65\x2E\x0D\x0D\x0A\x24\x00\x00\x00\x00\x00\x00\x00"; memset(&hdr, 0, sizeof(hdr)); hdr.e_magic = IMAGE_DOS_SIGNATURE; hdr.e_cblp = 0x0090; hdr.e_cp = 0x0003; hdr.e_cparhdr = 0x0004; hdr.e_maxalloc = 0xffff; hdr.e_sp = 0x00b8; hdr.e_lfarlc = 0x0040; hdr.e_lfanew = sizeof(hdr) + sizeof(dosdata); fwrite(&hdr, sizeof(hdr), 1, fd); fwrite(&dosdata, sizeof(dosdata), 1, fd); } void PE_sign_fwrite(FILE *fd) { uint32_t hdr; hdr = IMAGE_NT_SIGNATURE; fwrite(&hdr, sizeof(hdr), 1, fd); } void PE_file_fwrite(FILE *fd) { IMAGE_FILE hdr; memset(&hdr, 0, sizeof(hdr)); hdr.Machine = IMAGE_FILE_MACHINE_I386; hdr.NumberOfSections = PE_sections; hdr.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL32); hdr.Characteristics = PE_Characteristics; fwrite(&hdr, sizeof(hdr), 1, fd); } void PE_optional_fwrite(FILE *fd) { IMAGE_OPTIONAL32 hdr; memset(&hdr, 0, sizeof(hdr)); hdr.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC; hdr.SizeOfCode = PE_size_code; hdr.SizeOfInitializedData = PE_size_image - PE_size_code; hdr.AddressOfEntryPoint = PE_entry_point; hdr.BaseOfCode = PE_base_code; hdr.ImageBase = PE_image_base; hdr.SectionAlignment = PE_align; hdr.FileAlignment = PE_align; hdr.MajorOperatingSystemVersion = 4; hdr.MajorSubsystemVersion = 4; hdr.SizeOfImage = PE_size_image; hdr.SizeOfHeaders = PE_base_code; hdr.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; hdr.SizeOfStackReserve = 0x00100000; hdr.SizeOfStackCommit = 0x00001000; hdr.SizeOfHeapReserve = 0x00100000; hdr.SizeOfHeapCommit = 0x00001000; hdr.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; hdr.PE_DIR_ExportTable.VirtualAddress = PE_export_rva; hdr.PE_DIR_ExportTable.Size = PE_export_size; hdr.PE_DIR_ImportTable.VirtualAddress = PE_import_rva; hdr.PE_DIR_ImportTable.Size = PE_import_size; hdr.PE_DIR_Resource.VirtualAddress = PE_resource_rva; hdr.PE_DIR_Resource.Size = PE_resource_size; fwrite(&hdr, sizeof(hdr), 1, fd); } void PE_section_fwrite(FILE *fd) { IMAGE_SECTION_HEADER hdr; memset(&hdr, 0, sizeof(hdr)); strncpy(hdr.Name, PE_section_name, sizeof(hdr.Name)); hdr.Misc.VirtualSize = PE_virtual_size; hdr.VirtualAddress = PE_rva - PE_image_base; hdr.SizeOfRawData = PE_raw_size; hdr.PointerToRawData = PE_file_offset; hdr.Characteristics = PE_Characteristics; fwrite(&hdr, sizeof(hdr), 1, fd); }
is nobody going to help. I really need to do this.
Decryption algorithm: key = 'W' for all bytes: new_byte = byte^key key += new_byte+'W' Encryption algorithm: key = 'W' for all bytes: new_byte = byte^key key += byte^'W'
From: 3D 00 00 F0 00: cmp eax, 0xF00000 A3 B4 14 80 02: mov [0x28014B4], eax 7D 12: jge 0xB5478 ; Bug. We should ignore the OF (overflow flag). To: 3D 00 00 F0 00: cmp eax, 0xF00000 A3 B4 14 80 02: mov [0x28014B4], eax 73 12: jnb 0xB5478 ; Patched. Ignores the OF (overflow flag).
| DaniWeb Message | |
| Cancel Changes | |