KOrUPt

December 24, 2008

JmpFinder

Filed under: Coding, Tools — Tags: , , , , — KOrUPt @ 00:11

This is a tool I wrote to aid in exploitation of Windows PE files, its sole purpose is to find the location of instructions that jump into registers.

Those familiar with software exploitation will know why it’s useful to have the Virtual Address of a "JMP ESP" in memory…

I’ve released this tool on a few sites already but I figured I may as well post it here too…

Below is the source code, I’ve also uploaded a copy of the compiled version to this server…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// JmpFinder V1.4 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 :p
 
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;
    PIMAGE_SECTION_HEADER lpSecHdr;
	HANDLE hFile, hFileMap;
    LPBYTE hMap;
 
	char subBlock[256];
	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.4 By KOrUPt\n");
 
    if(argc < 2){
        printf("[-] Usage: %s <file> [IncrementByOpSize]\n", argv[0]);
        return 0;
    }
 
	if(argc == 3){
		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;
}

Download: http://korupt.co.uk/JmpFinder.exe

I look forward to reading your comments and such, if you’ve any questions please let me know! KOrUPt.

Powered by WordPress