//#define UPX_CRYPT /* CodeCrypt 0.0 Written by Tibbar @ GSO. You may use this code in your own projects for non-commercial purposes provided you give credit to the author. This is provided for educational purposes only. No legal reponsibility is held or accepted by the author for misuse of this code. */ #include #include #include "windows.h" #include "limits.h" void DetourFunctionStart(){} // this function is copied into EP for exe __declspec( naked )void DetourFoo() { _asm { push EAX; pop EAX; push EBX; pop EBX; NOP; mov EBX, 0x12345678; jmp EBX; // replaced by main with actual address NOP; } } void DetourFunctionEnd(){} void FunctionStart(){} // this function will be copied into binary and will become the entry point // it decrypts the code section and jmp's to the original entry point. __declspec( naked )void DecryptAndStart() { // retrieve original entry point, which will live at eip - 4 // and codesize at eip - 2 DWORD eipVal; DWORD codeSize; DWORD entryPt; _asm { // thanks to IDESPinner for this trick call jj; // think relative, this means go to next comand jj: pop EAX; // pop the EIP off the stack into EAX since it got pushed by the call mov EDX, EAX; add EDX, 0x33F; mov EBX, DWORD PTR [EDX]; // get seed add EDX, 0x4; // function pointer to LCG push EDX; push EBX; mov EBX, EAX; // save eip in ebx - keep it safe for a while mov ECX, [EAX - 0x9]; // no of sections push ECX; // push no of sections on stack mov EAX, 0x11; add EAX, ECX; add EAX, ECX; add EAX, ECX; add EAX, ECX; add EAX, ECX; add EAX, ECX; add EAX, ECX; add EAX, ECX; // each section info is 8 bytes mov EDX, EBX; sub EDX, EAX; mov ECX, [EDX]; // original entry point rva in ECX (EAX - 0x15 == storageSpot ) add EDX, 4; mov EAX, [EDX]; // imagebase in EAX add EDX, 4; // move to next data item (first section data) add ECX, EAX; // actual address of entrypoint in ECX push ECX; // keep it on stack for later push EAX; // image base on stack push EDX; // backward rva from eip initial to current data item /////////////CODE TO RESTORE DETOUR OVERWRITE/////// // we stored bytes stolen for detour at offset stored at storagespot-1 mov EBX, [EDX - 0xC]; // offset to stored copied EP code add EBX, EDX; // address of copied data sub EDX, EDX; detourRestoreLoopStart: mov EAX, [EBX]; CMP EDX, 0x20; // hardcoded detourLength jz detourRestoreLoopEnd; mov [ECX], EAX; add EDX, 4; add EBX, 4; add ECX, 4; jmp detourRestoreLoopStart; detourRestoreLoopEnd: // restore registers mov EDX, [ESP]; mov EAX, [ESP+0x4]; mov ECX, [ESP+0x8]; /////////////////////////////////////////////////// sub EDX, EDX; // zero at EDX outerLoop: mov ECX, [ESP+0xC]; // no of sections CMP EDX, ECX; jz theEnd; pop ECX; // was EDX earlier for backward rva from eip to data push EDX; // save counter for next loop // at ECX we have section data item 1 // inner loop innerLoop: // now retrieve VirtualAddress and Misc.VirtualSize for this section mov EBX,[ECX]; // VirtualAddress push EBX; mov EDX, [ECX + 0x4]; // Misc.VirtualSize mov EAX, [ESP + 0x8]; // get imagebase back add EAX, EBX; // so EAX is pointer to section start add ECX, 0x8; // fastforward to next section for next loop push ECX; // save this for next loop (eip at entry) // now we loop from [EAX] to [EAX+EDX] mov EBX, EAX; // put code start address in EBX add EDX, EAX; // last item of code to decrypt in EDX StartLoop: CMP EBX, EDX; // when these are the same, stop JZ StopLooping // get seed push EDX; push ECX; sub EAX, EAX; mov EAX, [ESP + 0x20]; // seed in EAX mov ECX, [ESP + 0x24]; // LCG foo in ECX mov DL, BYTE PTR [EBX] // get value at address EBX sub DL, AL; // decrypt it mov BYTE PTR [EBX], DL // put decrypted value back in right place inc EBX; call ECX; // get next LCG value mov [ESP + 0x20], EAX; // save LCG value pop ECX; pop EDX; jmp StartLoop; StopLooping: // now we must move to next section pop EBX; // get eip back pop EAX; // get section pointer back pop EDX; // get i inc EDX; // i++ push ECX; jmp outerLoop; theEnd: pop ECX; pop ECX; pop ECX; jmp ECX; } } void FunctionEnd(){} /* Assumes: EAX = x_r ESP = ret address (put there by call) returns x_r+1 in EAX */ void GenerateRandomNumberStart(){} __declspec( naked )void GenerateRandomNumber() { // x_(r+1) = a*x_r + c modulo m _asm { push EBX; push ECX; push EDX; mov EBX, 1277; mul EBX; // EAX*1277 answer in EDX add EAX, 0; // +c sub EDX,EDX; mov EBX, 131072; div EBX; // m mov EAX, EDX; // we only want a byte of it // mov BL, AL; // sub EAX, EAX; // mov AL, BL; pop EDX; pop ECX; pop EBX; ret; } /* x := y mod z; {unsigned remainder} mov( y, eax ); mov( 0, edx ); // Zero extend EAX into EDX. mod( z, edx:eax ); mov( edx, x ); // Note that remainder is in EDX. */ } void GenerateRandomNumberEnd(){} ULONG __fastcall GetSizeOfImage( IN PVOID pImageBase ) { // get DOS header IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase; // find an offset to the main PE header ... IMAGE_FILE_HEADER * pFileHeader = (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) + pDosHeader->e_lfanew + sizeof(IMAGE_NT_SIGNATURE)); // ... and optional PE header IMAGE_OPTIONAL_HEADER * pOptHeader = (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) + IMAGE_SIZEOF_FILE_HEADER); // calculate the size ULONG nSizeOfImage = pOptHeader->SizeOfHeaders; IMAGE_SECTION_HEADER * pSecHeader = (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) + pFileHeader->SizeOfOptionalHeader); // sum size of all image sections; this will result in the image // size for (int i = 0; i < pFileHeader->NumberOfSections; i++, pSecHeader++) nSizeOfImage += pSecHeader->SizeOfRawData; // return size of the executable return nSizeOfImage; } IMAGE_SECTION_HEADER* GetSectionHeader(IN PVOID pImageBase) { // get DOS header IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase; // find an offset to the main PE header ... IMAGE_FILE_HEADER * pFileHeader = (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) + pDosHeader->e_lfanew + sizeof(IMAGE_NT_SIGNATURE)); // ... and optional PE header IMAGE_OPTIONAL_HEADER * pOptHeader = (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) + IMAGE_SIZEOF_FILE_HEADER); // calculate the size ULONG nSizeOfImage = pOptHeader->SizeOfHeaders; IMAGE_SECTION_HEADER * pSecHeader = (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) + pFileHeader->SizeOfOptionalHeader); return pSecHeader; } PIMAGE_SECTION_HEADER FindLastVirtualSection(DWORD* pImageBase) { // get DOS header IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase; // get NT header IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew); // find an offset to the main PE header ... IMAGE_FILE_HEADER * pFileHeader = (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) + pDosHeader->e_lfanew + sizeof(IMAGE_NT_SIGNATURE)); // ... and optional PE header IMAGE_OPTIONAL_HEADER * pOptHeader = (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) + IMAGE_SIZEOF_FILE_HEADER); IMAGE_SECTION_HEADER * sectionHeader = (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) + pFileHeader->SizeOfOptionalHeader); DWORD newSectionOffset; DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections; DWORD currentMaxVA = 0; int pos = 0; IMAGE_SECTION_HEADER* tempHeader = sectionHeader; DWORD headerSize = sizeof(IMAGE_SECTION_HEADER); for(int i = 0; i < SectionNum; i++) { if((DWORD)(tempHeader->VirtualAddress) > currentMaxVA) { currentMaxVA = (DWORD)(tempHeader->VirtualAddress); pos = i; } tempHeader = (IMAGE_SECTION_HEADER*)((DWORD)tempHeader + headerSize); } IMAGE_SECTION_HEADER* lastSectionHeader = (IMAGE_SECTION_HEADER*)((DWORD)sectionHeader + pos*sizeof(IMAGE_SECTION_HEADER)); return lastSectionHeader; } PIMAGE_SECTION_HEADER FindLastPhysicalSection(DWORD* pImageBase) { // get DOS header IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase; // get NT header IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew); // find an offset to the main PE header ... IMAGE_FILE_HEADER * pFileHeader = (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) + pDosHeader->e_lfanew + sizeof(IMAGE_NT_SIGNATURE)); // ... and optional PE header IMAGE_OPTIONAL_HEADER * pOptHeader = (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) + IMAGE_SIZEOF_FILE_HEADER); IMAGE_SECTION_HEADER * sectionHeader = (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) + pFileHeader->SizeOfOptionalHeader); DWORD newSectionOffset; DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections; DWORD currentMaxPA = 0; int pos = 0; IMAGE_SECTION_HEADER* tempHeader = sectionHeader; DWORD headerSize = sizeof(IMAGE_SECTION_HEADER); for(int i = 0; i < SectionNum; i++) { if((DWORD)(tempHeader->PointerToRawData) > currentMaxPA) { currentMaxPA = (DWORD)(tempHeader->PointerToRawData); pos = i; } tempHeader = (IMAGE_SECTION_HEADER*)((DWORD)tempHeader + headerSize); } IMAGE_SECTION_HEADER* lastSectionHeader = (IMAGE_SECTION_HEADER*)((DWORD)sectionHeader + pos*sizeof(IMAGE_SECTION_HEADER)); return lastSectionHeader; } PIMAGE_SECTION_HEADER FindFirstSection(DWORD* pImageBase) { // get DOS header IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase; // get NT header IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew); // find an offset to the main PE header ... IMAGE_FILE_HEADER * pFileHeader = (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) + pDosHeader->e_lfanew + sizeof(IMAGE_NT_SIGNATURE)); // ... and optional PE header IMAGE_OPTIONAL_HEADER * pOptHeader = (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) + IMAGE_SIZEOF_FILE_HEADER); IMAGE_SECTION_HEADER * sectionHeader = (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) + pFileHeader->SizeOfOptionalHeader); return sectionHeader; } PIMAGE_SECTION_HEADER FindNextSection(DWORD* pImageBase, PIMAGE_SECTION_HEADER currentSection) { // get DOS header IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase; // get NT header IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew); // find an offset to the main PE header ... IMAGE_FILE_HEADER * pFileHeader = (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) + pDosHeader->e_lfanew + sizeof(IMAGE_NT_SIGNATURE)); // ... and optional PE header IMAGE_OPTIONAL_HEADER * pOptHeader = (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) + IMAGE_SIZEOF_FILE_HEADER); IMAGE_SECTION_HEADER * sectionHeader = (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) + pFileHeader->SizeOfOptionalHeader); DWORD newSectionOffset; DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections; if(SectionNum <= 1) return NULL; IMAGE_SECTION_HEADER* prevHeader = sectionHeader; IMAGE_SECTION_HEADER* currHeader = (IMAGE_SECTION_HEADER*)((DWORD)sectionHeader + sizeof(IMAGE_SECTION_HEADER)); DWORD headerSize = sizeof(IMAGE_SECTION_HEADER); for(int i = 0; i < SectionNum - 1; i++) { if(prevHeader == currentSection) return currHeader; prevHeader = currHeader; currHeader = (IMAGE_SECTION_HEADER*)((DWORD)currHeader + sizeof(IMAGE_SECTION_HEADER)); } return NULL; } PIMAGE_SECTION_HEADER FindSection(DWORD* pImageBase, DWORD sectionbase) { // get DOS header IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase; // get NT header IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew); // find an offset to the main PE header ... IMAGE_FILE_HEADER * pFileHeader = (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) + pDosHeader->e_lfanew + sizeof(IMAGE_NT_SIGNATURE)); // ... and optional PE header IMAGE_OPTIONAL_HEADER * pOptHeader = (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) + IMAGE_SIZEOF_FILE_HEADER); IMAGE_SECTION_HEADER * sectionHeader = (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) + pFileHeader->SizeOfOptionalHeader); DWORD newSectionOffset; DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections; DWORD currentMaxVA = 0; int pos = 0; IMAGE_SECTION_HEADER* tempHeader = sectionHeader; DWORD headerSize = sizeof(IMAGE_SECTION_HEADER); for(int i = 0; i < SectionNum; i++) { if(tempHeader->VirtualAddress == sectionbase) { return tempHeader; } tempHeader = (IMAGE_SECTION_HEADER*)((DWORD)tempHeader + headerSize); } return NULL; } void MakeAllSectionsWritable(DWORD* pImageBase) { // get DOS header IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase; // get NT header IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew); // find an offset to the main PE header ... IMAGE_FILE_HEADER * pFileHeader = (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) + pDosHeader->e_lfanew + sizeof(IMAGE_NT_SIGNATURE)); // ... and optional PE header IMAGE_OPTIONAL_HEADER * pOptHeader = (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) + IMAGE_SIZEOF_FILE_HEADER); IMAGE_SECTION_HEADER * sectionHeader = (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) + pFileHeader->SizeOfOptionalHeader); DWORD newSectionOffset; DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections; DWORD currentMaxVA = 0; int pos = 0; IMAGE_SECTION_HEADER* tempHeader = sectionHeader; DWORD headerSize = sizeof(IMAGE_SECTION_HEADER); for(int i = 0; i < SectionNum; i++) { tempHeader->Characteristics |= IMAGE_SCN_MEM_WRITE; tempHeader = (IMAGE_SECTION_HEADER*)((DWORD)tempHeader + headerSize); } return ; } PIMAGE_SECTION_HEADER AddSection(DWORD* pImageBase, DWORD codeVirtualStart, DWORD codeSize) { // get DOS header IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase; // get NT header IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew); // find an offset to the main PE header ... IMAGE_FILE_HEADER * pFileHeader = (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) + pDosHeader->e_lfanew + sizeof(IMAGE_NT_SIGNATURE)); // ... and optional PE header IMAGE_OPTIONAL_HEADER * pOptHeader = (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) + IMAGE_SIZEOF_FILE_HEADER); IMAGE_SECTION_HEADER * sectionHeader = (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) + pFileHeader->SizeOfOptionalHeader); DWORD newSectionOffset; DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections; newSectionOffset = (DWORD)sectionHeader +pNtHeaders->FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER) - (DWORD)pImageBase; // check whether there's room for a new section if(pNtHeaders->OptionalHeader.SizeOfHeaders<(newSectionOffset+sizeof(IMAGE_SECTION_HEADER))) { return NULL; } // increase SizeOf // create a new section IMAGE_SECTION_HEADER* newsection = (IMAGE_SECTION_HEADER*)((DWORD)pImageBase + newSectionOffset); // start to build the new section DWORD n = sizeof(IMAGE_SECTION_HEADER); CopyMemory(newsection, (IMAGE_SECTION_HEADER*)((DWORD)newsection - n), sizeof(IMAGE_SECTION_HEADER)); // VirtualAddress... // update the PE header pNtHeaders->FileHeader.NumberOfSections++; // newsection -> will be returned return (PIMAGE_SECTION_HEADER)newsection; } /* EncryptSection uses LCG to modify each byte. Seed is based on ticks, returned by function */ DWORD EncryptSection(IMAGE_SECTION_HEADER* codeSection, DWORD* imageBase, DWORD seed) { DWORD rawCodePosition = codeSection->PointerToRawData; DWORD virtualCodeSize = codeSection->SizeOfRawData;//->Misc.VirtualSize; DWORD startpos = (DWORD)imageBase + (DWORD)rawCodePosition; if(stricmp((char*)codeSection->Name, ".rsrc") == 0) startpos = startpos + 0x11; DWORD endpos = startpos + virtualCodeSize; // unprotect code BOOL diditwork = VirtualProtect((void*)startpos, virtualCodeSize, PAGE_READWRITE, NULL); DWORD x = GetLastError(); _asm { sub EAX, EAX; mov EAX, seed; mov EBX, startpos; mov EDX, endpos; StartLoop: CMP EBX, EDX; // when these are the same, stop JZ StopLooping mov CL, BYTE PTR [EBX] // get value at address EBX add CL, AL; // crypt it mov BYTE PTR [EBX], CL // put decrypted value back in right place inc EBX; call GenerateRandomNumber; // get next LCG value jmp StartLoop; StopLooping: mov seed, EAX; } return seed; } DWORD GetSeed() { DWORD seed = 0; seed = GetTickCount(); /* _asm { // get seed mov EBX, 0x7FFE0000; sub EAX, EAX; mov EAX, DWORD PTR [EBX]; mov seed, EAX; }*/ return seed; } int main( int argc, char* argv[] ) { if(argc != 3) { printf("*** Code Crypter 0.3 by Tibbar@GovernmentSecurity.org ***\n"); printf("*** ***\n"); printf("*** Usage: codecrypt filename.exe N ***\n"); printf("*** N = 0 --> encrypt all but .rsrc ***\n"); printf("*** N = 1 --> encrypt .rsrc as well ***\n"); printf("*** It also encrypts resources under assumption ***\n"); printf("*** that .idata is NOT merged with .rsrc ***\n"); printf("*** Disclaimer: This software is for educational ***\n"); printf("*** purposes only. No responsibility is held or ***\n"); printf("*** accepted for misuse. ***\n"); return 0; } BOOL cryptRSRC = FALSE; if(*argv[2] == '1') cryptRSRC = TRUE; HANDLE hFile = CreateFile( argv[1], GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == NULL) { printf("Invalid filename...exiting!"); return 0; } // get size of file LARGE_INTEGER bigInt; BOOL diditWork = GetFileSizeEx(hFile, &bigInt); // assume it's DWORD or less DWORD fileSize = bigInt.LowPart; if(fileSize + 0x2000 >= ULONG_MAX) return 0; HANDLE hFileMap = CreateFileMapping( hFile, NULL, PAGE_READWRITE,// | SEC_IMAGE, bigInt.HighPart, bigInt.LowPart + 0x2000 , "myfile"); if(hFileMap == NULL) { printf("Unable to create file mapping! Exiting..."); return 0; } // map file into memory LPVOID hMap = MapViewOfFile( hFileMap, FILE_MAP_WRITE, 0, 0, 0); if(hMap == NULL) { printf("Unable to map file into memory! Exiting..."); return 0; } HMODULE hModule = (HMODULE)hMap; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule; IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)hModule + pDosHeader->e_lfanew); IMAGE_OPTIONAL_HEADER* optionHeader =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hModule+pDosHeader->e_lfanew+24); VOID* pBaseCode = (VOID*)optionHeader->BaseOfCode; DWORD codeSize = optionHeader->SizeOfCode; IMAGE_SECTION_HEADER* sectionHeader = GetSectionHeader(hModule); // crypt sections IMAGE_SECTION_HEADER* sectionHeaderArray[20]; for(int i = 0 ;i < 20; i++) sectionHeaderArray[i] = NULL; BOOL encryptedSectionArray[20]; for(int i = 0 ;i < 20; i++) encryptedSectionArray[i] = FALSE; sectionHeaderArray[0] = FindFirstSection((DWORD*)hModule); DWORD seed = 0; while(true) { seed = GetSeed(); if(LOBYTE(seed) != 0) break; } DWORD currentLCGValue = 0; currentLCGValue = EncryptSection(sectionHeaderArray[0], (DWORD*)hModule, seed); encryptedSectionArray[0] = TRUE; int j = 1; while(true) { sectionHeaderArray[j] = FindNextSection((DWORD*)hModule, sectionHeaderArray[j-1]); if(sectionHeaderArray[j] == NULL) break; #ifdef UPX_CRYPT if(stricmp((char*)sectionHeaderArray[j]->Name, ".rsrc") == 0)// || stricmp((char*)sectionHeaderArray[j]->Name, "UPX1") == 0) { j++; continue; } #endif if(stricmp((char*)sectionHeaderArray[j]->Name, ".idata") == 0 || stricmp((char*)sectionHeaderArray[j]->Name, ".reloc") == 0 || stricmp((char*)sectionHeaderArray[j]->Name, ".rdata") == 0 || stricmp((char*)sectionHeaderArray[j]->Name, ".tls") == 0 || stricmp((char*)sectionHeaderArray[j]->Name, ".bss") == 0 || sectionHeaderArray[j]->SizeOfRawData == 0) { j++; continue; } if(cryptRSRC == FALSE && stricmp((char*)sectionHeaderArray[j]->Name, ".rsrc") == 0 ) { j++; continue; } encryptedSectionArray[j] = TRUE; currentLCGValue = EncryptSection(sectionHeaderArray[j], (DWORD*)hModule, currentLCGValue); j++; //break;////////////////////// } int numCrypedSections = 0; for(int i = 0 ;i < 20; i++) numCrypedSections += encryptedSectionArray[i]; // store rva from new entry point to original entry point at position pBaseCode + fileSize + 2 DWORD numOfSections = pNtHeaders->FileHeader.NumberOfSections; IMAGE_SECTION_HEADER* lastSection = FindLastPhysicalSection((DWORD*)hModule); #ifdef UPX_CRYPT DWORD* storageSpot = (DWORD*)((DWORD)hModule + (DWORD)lastSection->SizeOfRawData + (DWORD)lastSection->PointerToRawData);//(DWORD)lastSection->Misc.VirtualSize + (DWORD)lastSection->PointerToRawData); #else DWORD* storageSpot = (DWORD*)((DWORD)hModule + (DWORD)lastSection->SizeOfRawData + (DWORD)lastSection->PointerToRawData);//(DWORD)lastSection->Misc.VirtualSize + (DWORD)lastSection->PointerToRawData); #endif *(storageSpot) = (DWORD)optionHeader->AddressOfEntryPoint; *(storageSpot + 1) = (DWORD)optionHeader->ImageBase; int pos = 0; for(i = 0; i < numOfSections; i++) { if(encryptedSectionArray[i] == TRUE) { *(storageSpot + 2 + 2*pos) = (DWORD)sectionHeaderArray[i]->VirtualAddress; if(stricmp((char*)sectionHeaderArray[i]->Name, ".rsrc") == 0 ) *(storageSpot + 2 + 2*pos) += 0x11; *(storageSpot + 2 + 2*pos + 1) = (DWORD)sectionHeaderArray[i]->SizeOfRawData;//->Misc.VirtualSize; if(stricmp((char*)sectionHeaderArray[i]->Name, ".rsrc") == 0 ) *(storageSpot + 2 + 2*pos + 1) -= 0x11; pos ++; } } *(storageSpot + 2 + 2*numCrypedSections) = numCrypedSections;//pNtHeaders->FileHeader.NumberOfSections; // now we need to add our decryption routine to storageSpot + 4 (say) int dSize = (PBYTE)FunctionStart - (PBYTE)FunctionEnd; DWORD start = (DWORD) FunctionStart; DWORD end = (DWORD) FunctionEnd; DWORD length = (end - start); CopyMemory(storageSpot + 2 + 2*numCrypedSections + 1, DecryptAndStart, length); // next we must record our seed! *(storageSpot + 2 + 2*numCrypedSections + 1 + length + 1) = seed; // LCG function also: DWORD start1 = (DWORD) GenerateRandomNumberStart; DWORD end1 = (DWORD) GenerateRandomNumberEnd; DWORD length1 = (end - start); CopyMemory(storageSpot + 2 + 2*numCrypedSections + 1 + length + 2, GenerateRandomNumber, length1); // set new code as executable // IMAGE_SECTION_HEADER* newsection = AddSection((DWORD*)hModule, (DWORD)storageSpot + 4 - (DWORD)hModule, length); // to do this we will simply find the last section (i.e. one with highest RVA // and extend this by size needed // and set it to executable lastSection->Misc.VirtualSize += 0x2000; lastSection->SizeOfRawData += 0x2000; lastSection->Characteristics = IMAGE_SCN_MEM_WRITE| IMAGE_SCN_MEM_READ| IMAGE_SCN_MEM_EXECUTE| IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA| IMAGE_SCN_CNT_CODE;//0xE00000E0; // set new entry point optionHeader->SizeOfImage += 0x2000; optionHeader->SizeOfCode += 0x2000; optionHeader->SizeOfInitializedData += 0x2000; // finally we add a detour at EP to our stub DWORD stubEPrva = (DWORD)lastSection->VirtualAddress + (DWORD)lastSection->SizeOfRawData + 12 + 2*4*numCrypedSections - 0x2000; DWORD detourStart = (DWORD) DetourFunctionStart; DWORD detourEnd = (DWORD) DetourFunctionEnd; DWORD detourLength = (detourEnd - detourStart); // copy first few bytes to (storageSpot + 2 + 2*numCrypedSections + 1 + length) + 4 DWORD* target = (storageSpot + 2 + 2*numCrypedSections + 1 + length + 2 + length1 + 1) + 4; // store offset to it at storageSpot-1 *(storageSpot - 1) = (DWORD)target - (DWORD)storageSpot - 8; #ifdef UPX_CRYPT DWORD* pointerToEPonDisk = (DWORD*)((DWORD)hModule + (DWORD)optionHeader->AddressOfEntryPoint - ((DWORD)sectionHeaderArray[1]->VirtualAddress - (DWORD)sectionHeaderArray[1]->PointerToRawData )); #else DWORD* pointerToEPonDisk = (DWORD*)((DWORD)hModule + (DWORD)optionHeader->AddressOfEntryPoint - ((DWORD)sectionHeaderArray[0]->VirtualAddress - (DWORD)sectionHeaderArray[0]->PointerToRawData )); #endif CopyMemory(target, pointerToEPonDisk, detourLength); // now copy detour code to original EP CopyMemory(pointerToEPonDisk, DetourFoo, detourLength); // set correct jmp address *((WORD*)pointerToEPonDisk + 4) = HIWORD((DWORD)optionHeader->ImageBase + (DWORD)stubEPrva); *((WORD*)pointerToEPonDisk + 3) = LOWORD((DWORD)optionHeader->ImageBase + (DWORD)stubEPrva); // finally we need to set the main code section as writable for our stub to decrypt it! MakeAllSectionsWritable((DWORD*)hModule); printf("Crypted file successfully!"); }