├── Makefile ├── Nmakefile ├── README.md ├── godware.cpp ├── poc.c ├── poc2.c ├── pocs.sh ├── pocs ├── Makefile ├── far-jmp-32bit.c └── far-jmp-64bit.c └── rebuild.py /Makefile: -------------------------------------------------------------------------------- 1 | 2 | %.exe: %.c 3 | gcc -std=c99 -s -O2 -Wall -o $@ $^ 4 | 5 | default: poc2.exe 6 | ../../../ia32/bin/pin -t obj-ia32/godware.dll -- poc2.exe msgbox.exe 7 | 8 | tar: poc2.c Nmakefile godware.cpp rebuild.py obj-ia32/godware.dll poc2.exe \ 9 | msgbox.exe Makefile 10 | tar cf runpe-pin.tar $^ 11 | -------------------------------------------------------------------------------- /Nmakefile: -------------------------------------------------------------------------------- 1 | # nmake makefile for building the godware component 2 | # For description of targets and options, see Nmakefile in the root directory. 3 | 4 | !if "$(PIN_HOME)"=="" 5 | PIN_HOME=.. 6 | !endif 7 | 8 | # Define tools to be buit and tested 9 | COMMON_TOOLS=godware.dll 10 | 11 | # Include building and testing rules from the root Nmakefile. 12 | INCLUDE_SUB_RULES=1 13 | !INCLUDE $(PIN_HOME)\Nmakefile 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | godware 2 | ======= 3 | 4 | Short for Good Ware; it assists Reverse Engineers in the analysis of Windows 5 | Malware. 6 | -------------------------------------------------------------------------------- /godware.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "pin.h" 4 | 5 | // all our windows stuff.. needs its own namespace.. 6 | namespace W { 7 | #include 8 | } 9 | 10 | #define USHORT W::USHORT 11 | #define ULONG W::ULONG 12 | typedef wchar_t *PWCH; 13 | typedef char *PCHAR; 14 | #define HANDLE W::HANDLE 15 | typedef void *PVOID; 16 | #define RTL_MAX_DRIVE_LETTERS 32 17 | 18 | typedef struct _STRING { 19 | USHORT Length; 20 | USHORT MaximumLength; 21 | PCHAR Buffer; 22 | } STRING, *PSTRING, ANSI_STRING, *PANSI_STRING, OEM_STRING, *POEM_STRING; 23 | 24 | typedef struct _UNICODE_STRING { 25 | USHORT Length; 26 | USHORT MaximumLength; 27 | PWCH Buffer; 28 | } UNICODE_STRING, *PUNICODE_STRING; 29 | 30 | typedef struct _OBJECT_ATTRIBUTES { 31 | ULONG Length; 32 | HANDLE RootDirectory; 33 | PUNICODE_STRING ObjectName; 34 | ULONG Attributes; 35 | PVOID SecurityDescriptor; 36 | PVOID SecurityQualityOfService; 37 | } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; 38 | 39 | typedef struct _CURDIR { 40 | UNICODE_STRING DosPath; 41 | HANDLE Handle; 42 | } CURDIR, *PCURDIR; 43 | 44 | typedef struct _RTL_DRIVE_LETTER_CURDIR { 45 | USHORT Flags; 46 | USHORT Length; 47 | ULONG TimeStamp; 48 | STRING DosPath; 49 | } RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; 50 | 51 | typedef struct _RTL_USER_PROCESS_PARAMETERS { 52 | ULONG MaximumLength; 53 | ULONG Length; 54 | 55 | ULONG Flags; 56 | ULONG DebugFlags; 57 | 58 | HANDLE ConsoleHandle; 59 | ULONG ConsoleFlags; 60 | HANDLE StandardInput; 61 | HANDLE StandardOutput; 62 | HANDLE StandardError; 63 | 64 | CURDIR CurrentDirectory; 65 | UNICODE_STRING DllPath; 66 | UNICODE_STRING ImagePathName; 67 | UNICODE_STRING CommandLine; 68 | PVOID Environment; 69 | 70 | ULONG StartingX; 71 | ULONG StartingY; 72 | ULONG CountX; 73 | ULONG CountY; 74 | ULONG CountCharsX; 75 | ULONG CountCharsY; 76 | ULONG FillAttribute; 77 | 78 | ULONG WindowFlags; 79 | ULONG ShowWindowFlags; 80 | UNICODE_STRING WindowTitle; 81 | UNICODE_STRING DesktopInfo; 82 | UNICODE_STRING ShellInfo; 83 | UNICODE_STRING RuntimeData; 84 | RTL_DRIVE_LETTER_CURDIR CurrentDirectories[RTL_MAX_DRIVE_LETTERS]; 85 | 86 | ULONG EnvironmentSize; 87 | ULONG EnvironmentVersion; 88 | } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; 89 | 90 | #define MAX_SYSCALL (64 * 1024) 91 | static const char *g_syscall_names[MAX_SYSCALL]; 92 | 93 | // stole this lovely source code from the rreat library. 94 | static void enum_syscalls() 95 | { 96 | // no boundary checking at all, I assume ntdll is not malicious.. 97 | // besides that, we are in our own process, _should_ be fine.. 98 | unsigned char *image = (unsigned char *) W::GetModuleHandle("ntdll"); 99 | W::IMAGE_DOS_HEADER *dos_header = (W::IMAGE_DOS_HEADER *) image; 100 | W::IMAGE_NT_HEADERS *nt_headers = (W::IMAGE_NT_HEADERS *)(image + 101 | dos_header->e_lfanew); 102 | W::IMAGE_DATA_DIRECTORY *data_directory = &nt_headers-> 103 | OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 104 | W::IMAGE_EXPORT_DIRECTORY *export_directory = 105 | (W::IMAGE_EXPORT_DIRECTORY *)(image + data_directory->VirtualAddress); 106 | unsigned long *address_of_names = (unsigned long *)(image + 107 | export_directory->AddressOfNames); 108 | unsigned long *address_of_functions = (unsigned long *)(image + 109 | export_directory->AddressOfFunctions); 110 | unsigned short *address_of_name_ordinals = (unsigned short *)(image + 111 | export_directory->AddressOfNameOrdinals); 112 | unsigned long number_of_names = MIN(export_directory->NumberOfFunctions, 113 | export_directory->NumberOfNames); 114 | for (unsigned long i = 0; i < number_of_names; i++) { 115 | const char *name = (const char *)(image + address_of_names[i]); 116 | unsigned char *addr = image + address_of_functions[ 117 | address_of_name_ordinals[i]]; 118 | if(!memcmp(name, "Zw", 2) || !memcmp(name, "Nt", 2)) { 119 | // does the signature match? 120 | // either: mov eax, syscall_number ; mov ecx, some_value 121 | // or: mov eax, syscall_number ; xor ecx, ecx 122 | // or: mov eax, syscall_number ; mov edx, 0x7ffe0300 123 | if(*addr == 0xb8 && 124 | (addr[5] == 0xb9 || addr[5] == 0x33 || addr[5] == 0xba)) { 125 | unsigned long syscall_number = *(unsigned long *)(addr + 1); 126 | if(syscall_number < MAX_SYSCALL) { 127 | g_syscall_names[syscall_number] = name; 128 | } 129 | } 130 | } 131 | } 132 | } 133 | 134 | unsigned long syscall_name_to_number(const char *name) 135 | { 136 | for (unsigned long i = 0; i < MAX_SYSCALL; i++) { 137 | if(g_syscall_names[i] != NULL && 138 | !strcmp(g_syscall_names[i] + 2, name + 2)) { 139 | return i; 140 | } 141 | } 142 | printf("System Call %s not found!\n", name); 143 | return 0; 144 | } 145 | 146 | ADDRINT SYS_NtCreateUserProcess, SYS_NtWriteVirtualMemory, SYS_NtResumeThread; 147 | ADDRINT SYS_NtDuplicateObject, SYS_NtOpenThread, SYS_NtDelayExecution; 148 | ADDRINT SYS_NtOpenProcess, SYS_NtCreateProcess, SYS_NtCreateProcessEx; 149 | 150 | void init_common_syscalls() 151 | { 152 | SYS_NtCreateUserProcess = syscall_name_to_number("NtCreateUserProcess"); 153 | SYS_NtCreateProcess = syscall_name_to_number("NtCreateProcess"); 154 | SYS_NtCreateProcessEx = syscall_name_to_number("NtCreateProcessEx"); 155 | 156 | SYS_NtWriteVirtualMemory = syscall_name_to_number("NtWriteVirtualMemory"); 157 | SYS_NtResumeThread = syscall_name_to_number("NtResumeThread"); 158 | SYS_NtDuplicateObject = syscall_name_to_number("NtDuplicateObject"); 159 | SYS_NtOpenThread = syscall_name_to_number("NtOpenThread"); 160 | SYS_NtDelayExecution = syscall_name_to_number("NtDelayExecution"); 161 | SYS_NtOpenProcess = syscall_name_to_number("NtOpenProcess"); 162 | } 163 | 164 | typedef struct _syscall_t { 165 | ADDRINT syscall_number; 166 | union { 167 | ADDRINT args[16]; 168 | struct { 169 | ADDRINT arg0, arg1, arg2, arg3; 170 | ADDRINT arg4, arg5, arg6, arg7; 171 | }; 172 | }; 173 | } syscall_t; 174 | 175 | int g_process_handle_count = 0; 176 | HANDLE g_process_handle[256] = {0}; 177 | 178 | int g_thread_handle_count = 0; 179 | HANDLE g_thread_handle[256] = {0}; 180 | 181 | PIN_LOCK g_write_lock; 182 | FILE *g_file; 183 | 184 | // extract arguments to a system call in a syscall_entry_callback 185 | void syscall_get_arguments(CONTEXT *ctx, SYSCALL_STANDARD std, int count, ...) 186 | { 187 | va_list args; 188 | va_start(args, count); 189 | for (int i = 0; i < count; i++) { 190 | int index = va_arg(args, int); 191 | ADDRINT *ptr = va_arg(args, ADDRINT *); 192 | *ptr = PIN_GetSyscallArgument(ctx, std, index); 193 | } 194 | va_end(args); 195 | } 196 | 197 | void syscall_entry(THREADID thread_id, CONTEXT *ctx, SYSCALL_STANDARD std, 198 | void *v) 199 | { 200 | unsigned long syscall_number = PIN_GetSyscallNumber(ctx, std); 201 | if(syscall_number < MAX_SYSCALL) { 202 | const char *name = g_syscall_names[syscall_number]; 203 | printf("%d %d %s\n", thread_id, syscall_number, name); 204 | 205 | syscall_t *sc = &((syscall_t *) v)[thread_id]; 206 | sc->syscall_number = syscall_number; 207 | if(syscall_number == SYS_NtCreateUserProcess) { 208 | RTL_USER_PROCESS_PARAMETERS *process_parameters; 209 | ULONG create_thread_flags; 210 | 211 | syscall_get_arguments(ctx, std, 4, 0, &sc->arg0, 1, &sc->arg1, 212 | 8, &process_parameters, 7, &create_thread_flags); 213 | 214 | printf("image_name: %S\ncommand_line: %S\n", 215 | process_parameters->ImagePathName.Buffer, 216 | process_parameters->CommandLine.Buffer); 217 | 218 | printf("process_flags: 0x%08x\nthread_flags: 0x%08x\n", 219 | PIN_GetSyscallArgument(ctx, std, 6), 220 | PIN_GetSyscallArgument(ctx, std, 7)); 221 | 222 | if((create_thread_flags & 1) == 0) { 223 | printf("When creating a new process, please do suspend the " 224 | "thread initially!\n"); 225 | exit(0); 226 | } 227 | } 228 | else if(syscall_number == SYS_NtCreateProcess || 229 | syscall_number == SYS_NtCreateProcessEx) { 230 | OBJECT_ATTRIBUTES *object_attributes; 231 | syscall_get_arguments(ctx, std, 2, 0, &sc->arg0, 232 | 2, &object_attributes); 233 | 234 | if(object_attributes != NULL && 235 | object_attributes->ObjectName != NULL) { 236 | printf("image_name: %S\n", 237 | object_attributes->ObjectName->Buffer); 238 | } 239 | } 240 | else if(syscall_number == SYS_NtWriteVirtualMemory) { 241 | HANDLE process_handle; char *base_address, *buffer; 242 | 243 | syscall_get_arguments(ctx, std, 5, 0, &process_handle, 244 | 1, &base_address, 2, &buffer, 3, &sc->arg3, 4, &sc->arg4); 245 | 246 | GetLock(&g_write_lock, thread_id+1); 247 | 248 | // base address, size, buffer 249 | fwrite(&base_address, 1, sizeof(base_address), g_file); 250 | fwrite(&sc->arg3, 1, sizeof(sc->arg3), g_file); 251 | fwrite(buffer, 1, sc->arg3, g_file); 252 | fflush(g_file); 253 | 254 | printf("Writing 0x%08x bytes to 0x%08x\n", sc->arg3, 255 | base_address); 256 | 257 | ReleaseLock(&g_write_lock); 258 | } 259 | else if(syscall_number == SYS_NtResumeThread) { 260 | W::TerminateThread(g_thread_handle[0], 0); 261 | W::TerminateProcess(g_process_handle[0], 0); 262 | printf("We've finished dumping the remote process.\n"); 263 | exit(0); 264 | } 265 | else if(syscall_number == SYS_NtDuplicateObject) { 266 | printf("DuplicateHandle() not implemented yet!\n"); 267 | //exit(0); 268 | } 269 | else if(syscall_number == SYS_NtOpenThread) { 270 | printf("OpenThread() not implemented yet!\n"); 271 | //exit(0); 272 | } 273 | else if(syscall_number == SYS_NtOpenProcess) { 274 | printf("OpenProcess() not implemented yet!\n"); 275 | //exit(0); 276 | } 277 | else if(syscall_number == SYS_NtDelayExecution) { 278 | // we can ignore Sleep() calls like this 279 | W::LARGE_INTEGER *delay_interval; 280 | syscall_get_arguments(ctx, std, 1, 1, &delay_interval); 281 | if(delay_interval->QuadPart != 0) { 282 | printf("Skipped Sleep(%d)\n", 283 | -delay_interval->QuadPart / 10000); 284 | } 285 | delay_interval->QuadPart = 0; 286 | } 287 | } 288 | else { 289 | printf("dafuq?\n"); 290 | } 291 | } 292 | 293 | void syscall_exit(THREADID thread_id, CONTEXT *ctx, SYSCALL_STANDARD std, 294 | void *v) 295 | { 296 | syscall_t *sc = &((syscall_t *) v)[thread_id]; 297 | if(sc->syscall_number == SYS_NtCreateUserProcess) { 298 | g_process_handle[g_process_handle_count++] = *(HANDLE *) sc->arg0; 299 | g_thread_handle[g_thread_handle_count++] = *(HANDLE *) sc->arg1; 300 | } 301 | else if(sc->syscall_number == SYS_NtCreateProcess || 302 | sc->syscall_number == SYS_NtCreateProcessEx) { 303 | g_process_handle[g_process_handle_count++] = *(HANDLE *) sc->arg0; 304 | } 305 | } 306 | 307 | int main(int argc, char *argv[]) 308 | { 309 | if(PIN_Init(argc, argv)) { 310 | printf("Usage: %s [arguments]\n"); 311 | return 0; 312 | } 313 | 314 | g_file = fopen("logz.txt", "wb"); 315 | 316 | InitLock(&g_write_lock); 317 | 318 | enum_syscalls(); 319 | init_common_syscalls(); 320 | 321 | static syscall_t sc[256] = {0}; 322 | PIN_AddSyscallEntryFunction(&syscall_entry, &sc); 323 | PIN_AddSyscallExitFunction(&syscall_exit, &sc); 324 | 325 | PIN_StartProgram(); 326 | return 0; 327 | } 328 | -------------------------------------------------------------------------------- /poc.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | fclose(fopen("hoi", "r")); 6 | system("ls"); 7 | } 8 | -------------------------------------------------------------------------------- /poc2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef LONG (WINAPI *LP_NtUnmapViewOfSection)(HANDLE ProcessHandle, 5 | DWORD BaseAddress); 6 | 7 | char *FileToMem(const char *pszFileName) 8 | { 9 | char *lpBuffer = NULL; 10 | HANDLE hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, 11 | NULL, OPEN_EXISTING, 0, NULL); 12 | if(hFile == INVALID_HANDLE_VALUE) goto cleanup; 13 | 14 | DWORD dwSize = GetFileSize(hFile, NULL); 15 | if(dwSize == (DWORD) -1) goto cleanup; 16 | 17 | lpBuffer = VirtualAlloc(NULL, dwSize, MEM_COMMIT | MEM_RESERVE, 18 | PAGE_READWRITE); 19 | if(lpBuffer == NULL) goto cleanup; 20 | 21 | SetFilePointer(hFile, 0, NULL, FILE_BEGIN); 22 | DWORD dwRead; 23 | if(ReadFile(hFile, lpBuffer, dwSize, &dwRead, NULL) == FALSE || 24 | dwSize != dwRead) { 25 | goto cleanup; 26 | } 27 | 28 | CloseHandle(hFile); 29 | return lpBuffer; 30 | 31 | cleanup: 32 | if(lpBuffer != NULL) { 33 | VirtualFree(lpBuffer, 0, MEM_RELEASE); 34 | } 35 | if(hFile != INVALID_HANDLE_VALUE) { 36 | CloseHandle(hFile); 37 | } 38 | return NULL; 39 | } 40 | 41 | int ExecFile(const char *pszFilePath, char *lpFile) 42 | { 43 | DWORD dwBytes; void *lpImageBase = NULL; 44 | 45 | // check the image dos header 46 | IMAGE_DOS_HEADER *pImageDosHeader = (IMAGE_DOS_HEADER *) lpFile; 47 | if(pImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { 48 | return FALSE; 49 | } 50 | 51 | // check the image nt headers 52 | IMAGE_NT_HEADERS *pImageNtHeaders = (IMAGE_NT_HEADERS *)(lpFile + 53 | pImageDosHeader->e_lfanew); 54 | if(pImageNtHeaders->Signature != IMAGE_NT_SIGNATURE) { 55 | return FALSE; 56 | } 57 | 58 | // start the new process which we will overwrite later 59 | STARTUPINFOA StartupInfo = {sizeof(STARTUPINFOA)}; 60 | PROCESS_INFORMATION ProcessInformation = {0}; 61 | if(CreateProcess(pszFilePath, NULL, NULL, NULL, FALSE, 62 | CREATE_SUSPENDED, NULL, NULL, &StartupInfo, 63 | &ProcessInformation) == FALSE) { 64 | return FALSE; 65 | } 66 | 67 | // read the base address of the executable loaded in the 68 | // process which we will inject 69 | CONTEXT ctx = {CONTEXT_FULL}; DWORD dwImageBase; 70 | if(GetThreadContext(ProcessInformation.hThread, &ctx) == FALSE || 71 | ReadProcessMemory(ProcessInformation.hProcess, 72 | (void *)(ctx.Ebx + 8), &dwImageBase, 4, &dwBytes) == FALSE || 73 | dwBytes != 4) { 74 | goto cleanup; 75 | } 76 | 77 | // unmap the loaded binary if the base address conflicts 78 | // with the binary which we want to load 79 | if(dwImageBase == pImageNtHeaders->OptionalHeader.ImageBase) { 80 | LP_NtUnmapViewOfSection pNtUnmapViewOfSection = 81 | (LP_NtUnmapViewOfSection) GetProcAddress( 82 | GetModuleHandleA("ntdll.dll"), "NtUnmapViewOfSection"); 83 | pNtUnmapViewOfSection(ProcessInformation.hProcess, dwImageBase); 84 | } 85 | 86 | // allocate memory in the remote process for our binary 87 | lpImageBase = VirtualAllocEx(ProcessInformation.hProcess, 88 | (void *) pImageNtHeaders->OptionalHeader.ImageBase, 89 | pImageNtHeaders->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, 90 | PAGE_EXECUTE_READWRITE); 91 | if(lpImageBase == NULL) { 92 | goto cleanup; 93 | } 94 | 95 | // write the headers of our binary to the process 96 | if(WriteProcessMemory(ProcessInformation.hProcess, lpImageBase, lpFile, 97 | pImageNtHeaders->OptionalHeader.SizeOfHeaders, &dwBytes) 98 | == FALSE || 99 | dwBytes != pImageNtHeaders->OptionalHeader.SizeOfHeaders) { 100 | goto cleanup; 101 | } 102 | 103 | // enumerate all the sections in this binary 104 | IMAGE_SECTION_HEADER *pImageSectionHeader = (IMAGE_SECTION_HEADER *)( 105 | lpFile + pImageDosHeader->e_lfanew + sizeof(IMAGE_FILE_HEADER) + 106 | sizeof(DWORD) + pImageNtHeaders->FileHeader.SizeOfOptionalHeader); 107 | for (int i = 0; i < pImageNtHeaders->FileHeader.NumberOfSections; 108 | i++, pImageSectionHeader++) { 109 | 110 | // if this section has no size_of_raw_data, then we skip it because 111 | // there is nothing to write 112 | if(pImageSectionHeader->SizeOfRawData == 0) continue; 113 | 114 | // and write each section to the correct address in the process 115 | if(WriteProcessMemory(ProcessInformation.hProcess, 116 | (char *) lpImageBase + pImageSectionHeader->VirtualAddress, 117 | lpFile + pImageSectionHeader->PointerToRawData, 118 | pImageSectionHeader->SizeOfRawData, &dwBytes) == FALSE || 119 | pImageSectionHeader->SizeOfRawData != dwBytes) { 120 | goto cleanup; 121 | } 122 | } 123 | 124 | // write the new image base address 125 | if(WriteProcessMemory(ProcessInformation.hProcess, (void *)(ctx.Ebx + 8), 126 | &lpImageBase, 4, &dwBytes) == FALSE || dwBytes != 4) { 127 | goto cleanup; 128 | } 129 | 130 | // store the new entry point 131 | ctx.Eax = (DWORD) lpImageBase + 132 | pImageNtHeaders->OptionalHeader.AddressOfEntryPoint; 133 | 134 | // write the new context containing the updated entry point to the process 135 | SetThreadContext(ProcessInformation.hThread, &ctx); 136 | 137 | // resume the main thread, start the application 138 | ResumeThread(ProcessInformation.hThread); 139 | 140 | // clean up our resources 141 | CloseHandle(ProcessInformation.hThread); 142 | CloseHandle(ProcessInformation.hProcess); 143 | return TRUE; 144 | 145 | cleanup: 146 | // clean up our resources 147 | if(lpImageBase != NULL) { 148 | VirtualFreeEx(ProcessInformation.hProcess, lpImageBase, 0, 149 | MEM_RELEASE); 150 | } 151 | CloseHandle(ProcessInformation.hThread); 152 | CloseHandle(ProcessInformation.hProcess); 153 | return FALSE; 154 | } 155 | 156 | int main(int argc, char *argv[]) 157 | { 158 | if(argc != 2) { 159 | printf("Usage: %s \n", argv[0]); 160 | return 0; 161 | } 162 | 163 | char szFileName[MAX_PATH]; char *lpFile; 164 | 165 | lpFile = FileToMem(argv[1]); 166 | if(lpFile != NULL) { 167 | GetModuleFileName(NULL, szFileName, sizeof(szFileName)); 168 | ExecFile(szFileName, lpFile); 169 | VirtualFree(lpFile, 0, MEM_RELEASE); 170 | } 171 | return 0; 172 | } 173 | -------------------------------------------------------------------------------- /pocs.sh: -------------------------------------------------------------------------------- 1 | cd pocs 2 | make 3 | 4 | if [ $# -ne 1 ] 5 | then 6 | ../../../../ia32/bin/pin -t ../obj-ia32/godware.dll -- *.exe 7 | else 8 | ../../../../ia32/bin/pin -t ../obj-ia32/godware.dll -- $1.exe 9 | fi 10 | -------------------------------------------------------------------------------- /pocs/Makefile: -------------------------------------------------------------------------------- 1 | 2 | POCS := $(patsubst %.c, %.exe, $(wildcard *.c)) 3 | 4 | all: $(POCS) 5 | 6 | %.exe: %.c 7 | gcc -s -O2 -Wall -std=c99 -o $@ $^ 8 | -------------------------------------------------------------------------------- /pocs/far-jmp-32bit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | unsigned char sc[] = { 5 | 0xea, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 6 | 0xc3, 7 | }; 8 | 9 | int main() 10 | { 11 | DWORD old; 12 | VirtualProtect(sc, sizeof(sc), PAGE_EXECUTE_READWRITE, &old); 13 | 14 | *(unsigned long *)(sc + 1) = (unsigned long)(sc + 7); 15 | ((void(*)()) sc)(); 16 | } 17 | -------------------------------------------------------------------------------- /pocs/far-jmp-64bit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | unsigned char sc[] = { 5 | 0x9a, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 6 | 0xc3, 7 | 0xcb, 8 | }; 9 | 10 | int main() 11 | { 12 | DWORD old; 13 | VirtualProtect(sc, sizeof(sc), PAGE_EXECUTE_READWRITE, &old); 14 | 15 | *(unsigned long *)(sc + 1) = (unsigned long)(sc + 8); 16 | ((void(*)()) sc)(); 17 | } 18 | -------------------------------------------------------------------------------- /rebuild.py: -------------------------------------------------------------------------------- 1 | import sys, struct 2 | from ctypes import * 3 | 4 | class IMAGE_DOS_HEADER(Structure): 5 | _fields_ = [ 6 | ('e_magic', c_ushort), 7 | ('e_cblp', c_ushort), 8 | ('e_cp', c_ushort), 9 | ('e_crlc', c_ushort), 10 | ('e_cparhdr', c_ushort), 11 | ('e_minalloc', c_ushort), 12 | ('e_maxalloc', c_ushort), 13 | ('e_ss', c_ushort), 14 | ('e_sp', c_ushort), 15 | ('e_csum', c_ushort), 16 | ('e_ip', c_ushort), 17 | ('e_cs', c_ushort), 18 | ('e_lfarlc', c_ushort), 19 | ('e_ovno', c_ushort), 20 | ('e_res1', c_ushort * 4), 21 | ('e_oemid', c_ushort), 22 | ('e_oeminfo', c_ushort), 23 | ('e_res2', c_ushort * 10), 24 | ('e_lfanew', c_long) 25 | ] 26 | 27 | class IMAGE_FILE_HEADER(Structure): 28 | _fields_ = [ 29 | ('Machine', c_ushort), 30 | ('NumberOfSections', c_ushort), 31 | ('TimeDateStamp', c_uint), 32 | ('PointerToSymbolTable', c_uint), 33 | ('NumberOfSymbols', c_uint), 34 | ('SizeOfOptionalHeader', c_ushort), 35 | ('Characteristics', c_ushort) 36 | ] 37 | 38 | class IMAGE_DATA_DIRECTORY(Structure): 39 | _fields_ = [ 40 | ('VirtualAddress', c_uint), 41 | ('Size', c_uint) 42 | ] 43 | 44 | class IMAGE_OPTIONAL_HEADER(Structure): 45 | _fields_ = [ 46 | ('Magic', c_ushort), 47 | ('MajorLinkerVersion', c_ubyte), 48 | ('MinorLinkerVersion', c_ubyte), 49 | ('SizeOfCode', c_uint), 50 | ('SizeOfInitializedData', c_uint), 51 | ('SizeOfUninitializedData', c_uint), 52 | ('AddressOfEntryPoint', c_uint), 53 | ('BaseOfCode', c_uint), 54 | ('BaseOfData', c_uint), 55 | ('ImageBase', c_uint), 56 | ('SectionAlignment', c_uint), 57 | ('FileAlignment', c_uint), 58 | ('MajorOperatingSystemVersion', c_short), 59 | ('MinorOperatingSystemVersion', c_short), 60 | ('MajorImageVersion', c_short), 61 | ('MinorImageVersion', c_short), 62 | ('MajorSubsystemVersion', c_short), 63 | ('MinorSubsystemVersion', c_short), 64 | ('Win32VersionValue', c_uint), 65 | ('SizeOfImage', c_uint), 66 | ('SizeOfHeaders', c_uint), 67 | ('CheckSum', c_uint), 68 | ('Subsystem', c_short), 69 | ('DllCharacteristics', c_short), 70 | ('SizeOfStackReserve', c_uint), 71 | ('SizeOfStackCommit', c_uint), 72 | ('SizeOfHeapReserve', c_uint), 73 | ('SizeOfHeapCommit', c_uint), 74 | ('LoaderFlags', c_uint), 75 | ('NumberOfRvaAndSizes', c_uint) 76 | # omit the DataDirectory 77 | ] 78 | 79 | class IMAGE_NT_HEADERS(Structure): 80 | _fields_ = [ 81 | ('Signature', c_uint), 82 | ('FileHeader', IMAGE_FILE_HEADER), 83 | ('OptionalHeader', IMAGE_OPTIONAL_HEADER) 84 | ] 85 | 86 | IMAGE_SIZEOF_SHORT_NAME = 8 87 | 88 | class IMAGE_SECTION_HEADER_Misc(Union): 89 | _fields_ = [ 90 | ('PhysicalAddress', c_uint), 91 | ('VirtualSize', c_uint) 92 | ] 93 | 94 | class IMAGE_SECTION_HEADER(Structure): 95 | _fields_ = [ 96 | ('Name', c_char * IMAGE_SIZEOF_SHORT_NAME), 97 | ('Misc', IMAGE_SECTION_HEADER_Misc), 98 | ('VirtualAddress', c_uint), 99 | ('SizeOfRawData', c_uint), 100 | ('PointerToRawData', c_uint), 101 | ('PointerToRelocations', c_uint), 102 | ('PointerToLinenumbers', c_uint), 103 | ('NumberOfRelocations', c_short), 104 | ('NumberOfLinenumbers', c_short), 105 | ('Characteristics', c_uint) 106 | ] 107 | 108 | if __name__ == '__main__': 109 | if len(sys.argv) not in (2, 3): 110 | print 'Usage: %s [baseaddr]' % sys.argv[0] 111 | exit(0) 112 | 113 | # read the dump 114 | buf = file(sys.argv[1], 'rb').read() 115 | chunks = [] 116 | while len(buf): 117 | base_addr, length = struct.unpack('2I', buf[:8]) 118 | chunk, buf = buf[8:8+length], buf[8+length:] 119 | chunks.append((base_addr, length, chunk)) 120 | 121 | # sort on base address 122 | chunks = sorted(chunks, key=lambda x: x[0]) 123 | 124 | # print all the chunks 125 | print '\n'.join('0x%08x 0x%08x' % (x, y) for x, y, z in chunks) 126 | 127 | # determine base address 128 | base_address = sys.argv[2] if len(sys.argv) == 3 else 0x400000 129 | 130 | # TODO concat any sections that are split up, e.g. if there is a chunk at 131 | # address 0x401000 with length 1 and a chunk at 0x401001 with length 1, 132 | # then merge those chunks into one. 133 | # ... 134 | 135 | # dump all sections to file 136 | 137 | # find the section at the base address 138 | section = filter(lambda x: x[0] == base_address, chunks) 139 | assert len(section) == 1, 'No section found at the Base Address' 140 | 141 | # all the header data 142 | header_data = section[0][2] 143 | 144 | # read the image dos header 145 | image_dos_header = IMAGE_DOS_HEADER.from_buffer_copy(header_data) 146 | 147 | # read the image nt headers 148 | image_nt_headers = IMAGE_NT_HEADERS.from_buffer_copy(header_data, 149 | image_dos_header.e_lfanew) 150 | 151 | # output buffer 152 | buf = header_data 153 | 154 | # enumerate each section 155 | for x in xrange(image_nt_headers.FileHeader.NumberOfSections): 156 | 157 | # read the image section header 158 | image_section_header = IMAGE_SECTION_HEADER.from_buffer_copy( 159 | header_data, image_dos_header.e_lfanew + sizeof(c_uint) + 160 | sizeof(IMAGE_FILE_HEADER) + x * sizeof(IMAGE_SECTION_HEADER) + 161 | image_nt_headers.FileHeader.SizeOfOptionalHeader) 162 | 163 | # find the memory for this section 164 | data = filter(lambda x: x[0] == base_address + 165 | image_section_header.VirtualAddress, chunks) 166 | 167 | # prepend padding and append the data to the file 168 | buf += '\x00' * (image_section_header.PointerToRawData - len(buf)) 169 | buf += data[0][2] 170 | 171 | file(sys.argv[1] + '.out', 'wb').write(buf) 172 | --------------------------------------------------------------------------------