KOrUPt Posted November 27, 2008 Posted November 27, 2008 Ok so this small project was inspired by a question from Illuz1on, so shouts to him for that one smile.gif. I didn't spend very long on this so it may contain a few bugs(hopefully not). Basically it searches a specified PE(Portable-Executable) for all JMPs to registers and informs you of their position on disk and in memory with the intention of aiding in the exploitation of executables. Those who are familiar with Windows exploits or exploits in general will already know why it's useful to know where a "Jmp ESP" or similar instruction is located in memory... So I wont bother explaining that part of things here. // JmpFinder V1.1 By KOrUPt#pragma comment(linker,"/BASE:0x400000 /FILEALIGN:0x200 /MERGE:.rdata=.text /MERGE:.data=.text /SECTION:.text,EWR /IGNORE:4078")#pragma comment(lib, "version.lib")#include <windows.h>#include <stdio.h>struct LANGANDCODEPAGE { WORD wLanguage; WORD wCodePage;} *lpTranslate;DWORD FileToVa(DWORD dwFileAddr, PIMAGE_NT_HEADERS pNtHeaders) // By Napalm{ PIMAGE_SECTION_HEADER lpSecHdr = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeaders + sizeof(IMAGE_NT_HEADERS)); for(WORD wSections = 0; wSections < pNtHeaders->FileHeader.NumberOfSections; wSections++){ if(dwFileAddr >= lpSecHdr->PointerToRawData){ if(dwFileAddr < (lpSecHdr->PointerToRawData + lpSecHdr->SizeOfRawData)){ dwFileAddr -= lpSecHdr->PointerToRawData; dwFileAddr += (pNtHeaders->OptionalHeader.ImageBase + lpSecHdr->VirtualAddress); return dwFileAddr; } } lpSecHdr++; } return NULL;} int main(int argc, char* argv[]){ PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pNtHeaders; HANDLE hFile, hFileMap; LPBYTE hMap; CHAR key[2][12] = { "ProductName", "CSDVersion" }, subBlock[256], *buff; LPVOID versionInfo, versionOutput; DWORD dwSize, fsize, i; UINT generic = 0; printf("[*] Jmp Finder V1.1 By KOrUPt\n"); if(argc != 2){ printf("[-] Usage: %s [file]\n", argv[0]); return 0; } // map file hFile = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE){ printf("[-] Cannot open %s\n", argv[1]); return 0; } hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if(!hFileMap){ printf("[-] CreateFileMapping failed\n"); CloseHandle(hFile); return 0; } hMap = (LPBYTE)MapViewOfFile(hFileMap, FILE_READ_ACCESS, 0, 0, 0); if(!hMap){ printf("[-] MapViewOfFile failed\n"); CloseHandle(hFileMap); CloseHandle(hFile); return 0; } fsize = GetFileSize(hFile, 0); if(fsize < (sizeof(IMAGE_DOS_SIGNATURE) + sizeof(IMAGE_NT_HEADERS)) || fsize == INVALID_FILE_SIZE){ printf("[-] PE Headers not found\n"); CloseHandle(hFileMap); CloseHandle(hFile); return 0; } pDosHeader = (PIMAGE_DOS_HEADER)hMap; if(pDosHeader->e_magic != IMAGE_DOS_SIGNATURE){ printf("[-] DOS signature not found\n"); goto cleanup; } // get PE header pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)hMap + pDosHeader->e_lfanew); if(pNtHeaders->Signature != IMAGE_NT_SIGNATURE){ printf("[-] NT signature not found\n"); goto cleanup; } if(pNtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_I386){ printf("[-] Architecture not supported\n"); goto cleanup; } printf("[*] Scanning file: %s\n", argv[1]); // get version info if(dwSize = GetFileVersionInfoSize(argv[1], &i)){ versionInfo = malloc(dwSize); if(versionInfo){ if(GetFileVersionInfo(argv[1], 0, dwSize, versionInfo)){ if(VerQueryValue(versionInfo, "\\VarFileInfo\\Translation", (LPVOID *)&lpTranslate, &generic)){ wsprintf(subBlock, "\\StringFileInfo\\%04x%04x\\FileVersion", lpTranslate[0].wLanguage, lpTranslate[0].wCodePage); if(VerQueryValue(versionInfo, subBlock, (LPVOID *)&versionOutput, &generic)) printf("[+] File Version: %s\n\n", versionOutput); } } free(versionInfo); } } for(i = 0, generic = 0; i < fsize; i++){ if(hMap[i] == 0xFF){ if(hMap[i + 1] == 0xE0){ generic = 1; printf("[+] Jmp EAX located!"); } else if(hMap[i + 1] == 0xE1){ generic = 1; printf("[+] Jmp ECX located!"); } else if(hMap[i + 1] == 0xE2){ generic = 1; printf("[+] Jmp EDX located!"); } else if(hMap[i + 1] == 0xE3){ generic = 1; printf("[+] Jmp EBX located!"); } else if(hMap[i + 1] == 0xE4){ generic = 1; printf("[+] Jmp ESP located!"); } else if(hMap[i + 1] == 0xE5){ generic = 1; printf("[+] Jmp EBP located!"); } else if(hMap[i + 1] == 0xE6){ generic = 1; printf("[+] Jmp ESI located!"); } else if(hMap[i + 1] == 0xE7){ generic = 1; printf("[+] Jmp EDI located!"); } } if(generic) printf("\n[*] Virtual Address: 0x%08lX\n[*] FileOffset: 0x%08lX\n\n", FileToVa(i, pNtHeaders), i); generic = 0; } printf("[+] Happy Stack Smashing :)!\n"); cleanup: FlushViewOfFile(hMap, 0); UnmapViewOfFile(hMap); CloseHandle(hFileMap); CloseHandle(hFile); return 0;} I hope the code helps educate some . Let me know what you think. KOrUPt.
diablo2oo2 Posted November 27, 2008 Posted November 27, 2008 the problem is that you cant be sure that the bytes are assembler instructions. right? you must use a disassembler...
high6 Posted November 27, 2008 Posted November 27, 2008 If you limit this to just code sections and the section with the ep you should be set.
KOrUPt Posted November 27, 2008 Author Posted November 27, 2008 Nice idea's guys ... I'll modify the code and release an update shortly. @diablo2oo2: GamingMaster said the same thing (well near enough)... However I thought about that originally, but when I tried JMPing to the address(in this case 0x7C941EED) of a "JMP ESP" in ntdll.dll the instruction executed as I expected and execution was transferred to the stack, so I didn't see a reason to use an LDE as the potential false positives didn't seem to be false after all(as the instruction still executed as expected). KOrUPt.
metr0 Posted November 27, 2008 Posted November 27, 2008 Yep, the instruction is executed as expected, that's right. What diablo could've meant (just guessing here though I'm pretty sure it's the prob he referred to): If you want to modify existing code (without modifying jumps which are no "real" jumps at all but only part of another instruction), you'll have to make sure the jump you found is valid for the actual context. F. e., you want to replace all "nop nop" in a program with "jmp $+2". You search for "9090" and replace it with "eb00". But if you encounter a call with opcodes like "e800019090", you change it to "e80001eb00", which changes the call itself. Anyway, it seems like you only want to call that specific jump you've been searching (obfuscation? ), thus your method should work fine.
KOrUPt Posted December 5, 2008 Author Posted December 5, 2008 Just thought I'd post an update ... Improved the code, as you can likely see below. // JmpFinder V1.3 By KOrUPt with credit Napalm for helping :)#pragma comment(linker,"/BASE:0x400000 /FILEALIGN:0x200 /MERGE:.rdata=.text /MERGE:.data=.text /SECTION:.text,EWR /IGNORE:4078")#pragma comment(lib, "version.lib")#include <windows.h>#include <stdio.h>#include "x86opsize.cpp" // < hackjob for scITE :pstruct LANGANDCODEPAGE { WORD wLanguage; WORD wCodePage;} *lpTranslate;DWORD FileToVa(DWORD dwFileAddr, PIMAGE_NT_HEADERS pNtHeaders) // By Napalm{ PIMAGE_SECTION_HEADER lpSecHdr = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeaders + sizeof(IMAGE_NT_HEADERS)); for(WORD wSections = 0; wSections < pNtHeaders->FileHeader.NumberOfSections; wSections++){ if(dwFileAddr >= lpSecHdr->PointerToRawData){ if(dwFileAddr < (lpSecHdr->PointerToRawData + lpSecHdr->SizeOfRawData)){ dwFileAddr -= lpSecHdr->PointerToRawData; dwFileAddr += (pNtHeaders->OptionalHeader.ImageBase + lpSecHdr->VirtualAddress); return dwFileAddr; } } lpSecHdr++; } return NULL;} int main(int argc, char* argv[]){ PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pNtHeaders; PIMAGE_SECTION_HEADER lpSecHdr; HANDLE hFile, hFileMap; LPBYTE hMap; char subBlock[256], *buff; char jmpTable[][4] = { "EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI", 0 }; LPVOID versionInfo, versionOutput; DWORD dwSize, fsize, i, useOpsize = 0; UINT generic = 0; printf("[*] Jmp Finder V1.3 By KOrUPt\n"); if(argc != 3){ printf("[-] Usage: %s [file] [IncrementByOpSize]\n", argv[0]); return 0; } if(argv[2][0] == 'y'){ printf("[*] Incrementing by instruction size\n"); useOpsize = 1; } // map file hFile = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE){ printf("[-] Cannot open %s\n", argv[1]); return 0; } hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if(!hFileMap){ printf("[-] CreateFileMapping failed\n"); CloseHandle(hFile); return 0; } hMap = (LPBYTE)MapViewOfFile(hFileMap, FILE_READ_ACCESS, 0, 0, 0); if(!hMap){ printf("[-] MapViewOfFile failed\n"); CloseHandle(hFileMap); CloseHandle(hFile); return 0; } fsize = GetFileSize(hFile, 0); if(fsize < (sizeof(IMAGE_DOS_SIGNATURE) + sizeof(IMAGE_NT_HEADERS)) || fsize == INVALID_FILE_SIZE){ printf("[-] PE Headers not found\n"); CloseHandle(hFileMap); CloseHandle(hFile); return 0; } pDosHeader = (PIMAGE_DOS_HEADER)hMap; if(pDosHeader->e_magic != IMAGE_DOS_SIGNATURE){ printf("[-] DOS signature not found\n"); goto cleanup; } pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)hMap + pDosHeader->e_lfanew); if(pNtHeaders->Signature != IMAGE_NT_SIGNATURE){ printf("[-] NT signature not found\n"); goto cleanup; } if(pNtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_I386){ printf("[-] Architecture not supported\n"); goto cleanup; } printf("[*] Scanning file: %s\n", argv[1]); // get version info if((dwSize = GetFileVersionInfoSize(argv[1], &i))){ versionInfo = malloc(dwSize); if(versionInfo){ if(GetFileVersionInfo(argv[1], 0, dwSize, versionInfo)){ if(VerQueryValue(versionInfo, "\\VarFileInfo\\Translation", (LPVOID *)&lpTranslate, &generic)){ wsprintf(subBlock, "\\StringFileInfo\\%04x%04x\\FileVersion", lpTranslate[0].wLanguage, lpTranslate[0].wCodePage); if(VerQueryValue(versionInfo, subBlock, (LPVOID *)&versionOutput, &generic)) printf("[+] File Version: %s\n\n", versionOutput); } } free(versionInfo); } } lpSecHdr = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeaders + sizeof(IMAGE_NT_HEADERS)); for(i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++){ if(lpSecHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE){ BYTE bOpcode2; LPBYTE lpStart = (hMap + lpSecHdr->PointerToRawData); LPBYTE lpEnd = (lpStart + lpSecHdr->SizeOfRawData); while(lpStart < lpEnd){ bOpcode2 = *(lpStart + 1); if(*lpStart == 0xFF && bOpcode2 >= 0xE0 && bOpcode2 <= 0xE7){ printf("%Jmp %s located!", jmpTable[bOpcode2 & 0xF]); printf("\n[*] Virtual Address: 0x%08lX\n[*] FileOffset: 0x%08lX\n\n", FileToVa((lpStart - hMap), pNtHeaders), (lpStart - hMap)); } if(useOpsize) lpStart += x86opsize(lpStart); else lpStart++; } } lpSecHdr++; } printf("[+] Happy Stack Smashing :)!\n"); cleanup: FlushViewOfFile(hMap, 0); UnmapViewOfFile(hMap); CloseHandle(hFileMap); CloseHandle(hFile); return 0;} Let me know what you think . KOrUPt.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now