Jump to content
Tuts 4 You

[C] JmpFinder


KOrUPt

Recommended Posts

Posted

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.

Posted

the problem is that you cant be sure that the bytes are assembler instructions. right? you must use a disassembler...

Posted

If you limit this to just code sections and the section with the ep you should be set.

Posted

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.

Posted

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.

Posted

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.

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...