bool SymbolMap::GetSymbolInfo(SymbolInfo *info, u32 address, SymbolType symmask) const { u32 functionAddress = -1; u32 dataAddress = -1; if (symmask & ST_FUNCTION) functionAddress = GetFunctionStart(address); if (symmask & ST_DATA) dataAddress = GetDataStart(address); if (functionAddress == -1 || dataAddress == -1) { if (functionAddress != -1) { if (info != NULL) { info->type = ST_FUNCTION; info->address = functionAddress; info->size = GetFunctionSize(functionAddress); } return true; } if (dataAddress != -1) { if (info != NULL) { info->type = ST_DATA; info->address = dataAddress; info->size = GetDataSize(dataAddress); } return true; } return false; } // if both exist, return the function if (info != NULL) { info->type = ST_FUNCTION; info->address = functionAddress; info->size = GetFunctionSize(functionAddress); } return true; }
std::vector<SymbolEntry> SymbolMap::GetAllSymbols(SymbolType symmask) { std::vector<SymbolEntry> result; if (symmask & ST_FUNCTION) { lock_guard guard(lock_); for (auto it = activeFunctions.begin(); it != activeFunctions.end(); it++) { SymbolEntry entry; entry.address = it->first; entry.size = GetFunctionSize(entry.address); const char* name = GetLabelName(entry.address); if (name != NULL) entry.name = name; result.push_back(entry); } } if (symmask & ST_DATA) { lock_guard guard(lock_); for (auto it = activeData.begin(); it != activeData.end(); it++) { SymbolEntry entry; entry.address = it->first; entry.size = GetDataSize(entry.address); const char* name = GetLabelName(entry.address); if (name != NULL) entry.name = name; result.push_back(entry); } } return result; }
// Taken from Ashkbiz Danehkar's PE protector code: // (http://www.codeproject.com/cpp/peprotector1.asp) // // Return the bytes of a named function. char* CopyFunction(void (*Body)(void)) { DWORD dwSize=GetFunctionSize(Body); char* pFuncBody=(char *) Body; char* filebuff=new char[dwSize+1]; CopyMemory(filebuff,pFuncBody,dwSize); return(filebuff); }
//************************************ // Method: CJmpSwapDetour // FullName: CJmpSwapDetour::CJmpSwapDetour // Access: public // Parameter: void * function // Parameter: void * detour //************************************ CJmpSwapDetour::CJmpSwapDetour(void *function, void *detour) : m_bDetoured(false), m_Target(function), m_Detour(detour), m_Jmp(NULL), m_JmpSize(0) { m_Target = FollowJmp(m_Target); m_Detour = FollowJmp(m_Detour); m_FunctionSize = GetFunctionSize(m_Target); m_OriginalBytes = new unsigned char[m_FunctionSize]; memcpy_s(m_OriginalBytes, m_FunctionSize, m_Target, m_FunctionSize); BuildJump(m_Detour); Swap(); }
bool SymbolMap::GetSymbolInfo(SymbolInfo *info, u32 address, SymbolType symmask) const { u32 functionAddress = INVALID_ADDRESS; u32 dataAddress = INVALID_ADDRESS; if (symmask & ST_FUNCTION) { functionAddress = GetFunctionStart(address); // If both are found, we always return the function, so just do that early. if (functionAddress != INVALID_ADDRESS) { if (info != NULL) { info->type = ST_FUNCTION; info->address = functionAddress; info->size = GetFunctionSize(functionAddress); info->moduleAddress = GetFunctionModuleAddress(functionAddress); } return true; } } if (symmask & ST_DATA) { dataAddress = GetDataStart(address); if (dataAddress != INVALID_ADDRESS) { if (info != NULL) { info->type = ST_DATA; info->address = dataAddress; info->size = GetDataSize(dataAddress); info->moduleAddress = GetDataModuleAddress(dataAddress); } return true; } } return false; }
// Most of the work is done in main()... int main( int argc, char* argv[] ) { // Print out help message if needed. if (argc != 2) { printf("*** Code Crypt 0.0 by [email protected] ***\n"); printf("*** ***\n"); printf("*** Usage: codecrypt filename.exe ***\n"); printf("*** Will encrypt the codesection to avoid detection ***\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; } // The file to pack is the 1st argument. LPCSTR fileName = argv[1]; // Open the .exe file to be packed. HANDLE hFile = CreateFileA( fileName, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // Did the file open work? if (hFile == INVALID_HANDLE_VALUE) { DWORD x = GetLastError(); // No, get out. printf("Cannot open file '%s'...exiting!\n", argv[1]); char *buf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,x,0, (LPTSTR) &buf,0,NULL); printf("Error: %d, Error Code:%d\n", buf, x); return 1; } // Get size of file. This is needed because we need to tell the // CreateFileMapping function to add memory to the end of the // memory-mapped file. We will later use this memory to add in the // unpacker stub and its required data. LARGE_INTEGER bigInt; BOOL r = GetFileSizeEx(hFile, &bigInt); if (!r) { printf("Cannot get file size.\n"); return 1; } // Is the file too big to add in the unpacker stub? DWORD fileSize = bigInt.LowPart; if (fileSize + 0x2000 >= ULONG_MAX) { printf("The file is too big to pack.\n"); return 1; } // Create a handle to a memory mapped file. Note that this does not // actually map the file, it just creates the handle that will actually be // mapped later. Note that extra space is allocated at the end to // the mapped file for the unpacker stub. HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, bigInt.HighPart, bigInt.LowPart + 0x2000 , NULL); // Did creating the file mapping handle work? if (hFileMap == NULL) { printf("Unable to create file mapping! Exiting..."); return 1; } // Map the .exe file into memory. The map is set up so we can read and // write to it. LPVOID hMap = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); // Did mapping the file to memory work? if (hMap == NULL) { printf("Unable to map file into memory! Exiting..."); return 1; } // Get the DOS header from the .exe file. This is the 1st thing in the // file. PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hMap; // This packer only works with .exe files. Make sure we have one. // The e_magic field tells us what sort of file this is. if (!(pDosHeader->e_magic == IMAGE_DOS_SIGNATURE)) { printf("This packer only works with .exe files.\n"); return 1; } // Get the IMAGE_NT_HEADER. This has 3 fields, the signature (which should // be set 0x00004550 for valid PE files), the file header, and the // optional file header. PIMAGE_NT_HEADERS pNTHeader; // The e_lfanew field in the DOS header gives us the offset to the // IMAGE_NT_HEADER. pNTHeader = MakePtr(PIMAGE_NT_HEADERS, pDosHeader, pDosHeader->e_lfanew); // Check to make sure this is a PE file we are working with. if (!(pNTHeader->Signature == IMAGE_NT_SIGNATURE)) { printf("This packer only works with PE files.\n"); printf("Signature for PE files is %x. Current signature is %x\n", IMAGE_NT_SIGNATURE, pNTHeader->Signature); return 1; } // The entire .exe image is stored in a HMODULE structure. Cast the memory // mapped file so it can be viewed as an HMODULE. HMODULE *hModule = (HMODULE *) hMap; // Grab a pointer to the IMAGE_OPTIONAL_HEADER structure, which contains // information about the size of the code and all data sections, where to // find the sections, etc. // // The IMAGE_OPTIONAL_HEADER structure is contained in the IMAGE_NT_HEADER // in the OptionalHeader field. // // Note that we are assuming that we are working with a 32bit executable. PIMAGE_OPTIONAL_HEADER32 optionHeader = (PIMAGE_OPTIONAL_HEADER32) &(pNTHeader->OptionalHeader); // Get the RVA (relative virtual address) of the first byte of code when // loaded into memory. To find the actual address of the code add the load // address (in this case the address of hModule) to the RVA. VOID* baseCodeRVA = (VOID*)optionHeader->BaseOfCode; // Get the combined size of all code sections. DWORD codeSize = optionHeader->SizeOfCode; // TCC does not seem to set the SizeOfCode field, so executables // compiled with TCC cannot be packed with this packer. if (codeSize < 1) { printf("SizeOfCode field is < 1. Cannot pack.\n"); printf("The execuatble may have been compiled with TCC.\n"); return 1; } // After the MAGE_NT_HEADERS is the section table. The section table is an // array of IMAGE_SECTION_HEADERs structures. An IMAGE_SECTION_HEADER // provides information about its associated section. // // Use the IMAGE_FIRST_SECTION macro defined in winnt.h to get the address // of the 1st IMAGE_SECTION_HEADER. // DQ (4/23/2017): I don't see that this macro will work with WINE (modified to support testing). // IMAGE_SECTION_HEADER* firstSectionHeader = // IMAGE_FIRST_SECTION32(pNTHeader); IMAGE_SECTION_HEADER* firstSectionHeader = NULL; // Get a pointer to the code block. The code block is found by adding the // base load address to the code RVA. PVOID codePtr = MakePtr(void *, hModule, baseCodeRVA); // Unprotect the code so we can encrypt it in place. DWORD oldProt = 0; BOOL diditwork = VirtualProtect(codePtr, codeSize, PAGE_READWRITE, &oldProt); // Did the code unprotection work? if (!diditwork) { DWORD x = GetLastError(); printf("Cannot unprotect code (error code %d).\n", x); return 0; } // Find the section containing the code. We have already // calculated the code relative virtual base address // (baseCodeRVA), so now we need to find the section whose base // RVA is the same as the RVA of the code. IMAGE_SECTION_HEADER* codeSection = FindSection(firstSectionHeader, pNTHeader->FileHeader.NumberOfSections, (DWORD) baseCodeRVA); // Can we find the section with the code? if (codeSection == NULL) { printf("Cannot find code section.\n"); return 0; } // Get the raw memory address (inside HMODULE) and size of the code. DWORD rawCodePosition = codeSection->PointerToRawData; DWORD virtualCodeSize = codeSection->Misc.VirtualSize; // Compute the actual, in-memory start and end address of the code // block. DWORD startpos = (DWORD)hModule + (DWORD)rawCodePosition; DWORD endpos = startpos + virtualCodeSize; // Encrypt the code by incrementing each byte in the code by 1. printf("Starting to encrypt code section...\n"); DWORD currAddr; for (currAddr = startpos; currAddr < endpos; currAddr++) { (*((char *) currAddr))++; } printf("Done encrypting code section.\n"); // Get the last section. We will be tacking the unpacking code // onto the end of the last section (if we have room). IMAGE_SECTION_HEADER* lastSection = FindLastSection(firstSectionHeader, pNTHeader->FileHeader.NumberOfSections); char sectName[10]; int i; for (i = 0; i < 8; i++) { sectName[i] = lastSection->Name[i]; } sectName[8] = '\0'; printf("Adding stub to section: name = %s, Raw size = %d, Raw Data ptr = %d\n", sectName, lastSection->SizeOfRawData, lastSection->PointerToRawData); // We will be adding the unpacker stub to the last section in the // PE file. In that section, we will be adding the unpacker stub // code right after the existing data in the section. DWORD* storageSpot = (DWORD*)((DWORD)hModule + (DWORD)lastSection->PointerToRawData + (DWORD)lastSection->SizeOfRawData); // Get the unpacking code and store it in a contiguous chunk of memory. char *decryptRoutine = CopyFunction(&DecryptAndStart); DWORD decryptSize = GetFunctionSize(&DecryptAndStart); if (decryptSize > 0x2000) { printf("Decryption routine too large.\n"); return 1; } printf("Size of stub = %d\n", decryptSize); // Now start putting data into memory as it will be laid out in // the packed executable. // Track the # of pieces of initialization data added. int numInitData = 0; // Store the RVA of the packed code furthest away from the stub. *(storageSpot + numInitData++) = (DWORD)baseCodeRVA; // Store original code entry RVA at storagespot next closest to // the stub. *(storageSpot + numInitData++) = (DWORD)optionHeader->AddressOfEntryPoint; // Store the image base (used with the code base RVA to figure out // where the code to unpack is in memory in the unpacker stub) at // the next closest spot. *(storageSpot + numInitData++) = (DWORD)optionHeader->ImageBase; // Store size of code (in bytes) to unpack at the spot closest to // the stub. *(storageSpot + numInitData++) = virtualCodeSize; // Add our decryption routine to storageSpot + (# of data DWORDS // added). The +(# of data DWORDS written) is there so that the // unpacker stub data added above is not overwritten by the stub. // // Note that storageSpot is a pointer to a DWORD, so adding 1 to // storageSpot advances by 1 DWORD, not 1 BYTE. memcpy(storageSpot + numInitData, decryptRoutine, decryptSize); // Now update the header for the last section (i.e. one with // highest RVA) and extend this by size needed and set it to // executable. // Add the size of the unpacker stub and its initialization data // to all of the size tracking fields in the IMAGE_OPTIONAL_HEADER. optionHeader->SizeOfImage += 0x2000; optionHeader->SizeOfCode += 0x2000; optionHeader->SizeOfInitializedData += 0x2000; // Set the new initial entry point to the unpacker stub. optionHeader->AddressOfEntryPoint = // Start in last section... (DWORD)lastSection->VirtualAddress + // At the end of its original data... (DWORD)lastSection->SizeOfRawData + // Past the unpacker stub initialization data (4 DWORDs). (sizeof(DWORD))*numInitData; // Add the size of the unpacker stub and its initialization data // to all of the size tracking fields the last section header. 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; // Finally we need to set the main code section as writable for // our stub to decrypt it. We will do this by making ALL sections // writable. MakeAllSectionsWritable(firstSectionHeader, pNTHeader->FileHeader.NumberOfSections); // Close the packed file. CloseHandle(hFile); }