PDA

View Full Version : Packed Executable but with Missing DLLs


live_dont_exist
November 13th, 2011, 04:26
Hi All,
I am back with another problem . Actually I think I have solved this one but would like to know if there are any good reads about this situation. For me as a relative newbie it was an interesting problem.

This time I was analyzing an exe which was packed with FSG 2.0 [PEID, RDG, ProtectionID]. I could successfully unpack it after following tutorials on-line. The code after unpacking too seemed unreadable though. After some troubleshooting, I found that the code was encrypted/self modified. The encryption routine ran and rewrote a lot of the code starting from the entry point itself. After this the code seemed to make sense.

I didn't want to go through this process again; so I dumped the decrypted code and formed a new executable. Reloaded into Olly. Worked fine. Then started stepping through, till I came to a function which I am sure is one to query a registry key; but it was in the form as give below:

00401BF6 FF15 5E144000 CALL DWORD PTR DS:[40145E]

Stepping over this call, caused the program to crash with an 'Access violation' error. Similar behavior was found in 2 more APIs.

So then I thought, this means that the packer (FSG) has destroyed the IAT and I have to reconstruct. However trying to do so using Imprec failed. This means I have to repair the IAT manually. Now here I tried to read many tutorials but am a little stuck. The reason is as follows:

All the APIs which are related to kernel32.dll seem perfectly fine and Olly can analyze them. It is the other APIs that are causing a problem. Even this I can sort of understand - Maybe the packer messed up everything except Kernel32.dll. This means that I have to repair the IAT for all the other DLLs/APIs only.

Now the problem is that the API in question RegQueryValueExA belongs to advapi32.dll, which does not even seem to be loaded by this EXE. [Ctrl + E in Olly does not show it]. However 40145E does contain DS:[0040145E]=77DDEAF4 which looks very much like an API address start point. But I cant follow this call... there is nothing at 77DDEAF4.

So I used this tool called CFF Explorer and added the DLL from my machine into the EXE and repaired the Import Table. Reran the Exec, this time it worked and this is what I could see:

DS:[0040145E]=77DDEAF4 (advapi32.RegCreateKeyExA)

Repeating this process for every missing DLL helped me to fully reconstruct this EXE. Now the question is:

a) Why would malware use this technique? Of dropping DLLs out..its bad for the malware itself..rt? As it can't run?
b) How would one be able to solve this problem without the usage of a tool like CFF Explorer in a reliable way?

I read tutorials to use Imprec and finding the start and end of the IAT and I think I understand that part but what about a problem like this. When the DLL itself is missing? How do you solve it manually?

I have attached lots of screenshots and all 3 files as an attachment. Please have a look there if you don't understand or ping me.

Thanks
Arvind

blabberer
November 13th, 2011, 08:19
you must have done something wrong while unpacking
i unpacked it and dont find the problem you mention

string apis modules all seem to be intact

what is your oep

Code:

Text strings referenced in unpack_f:
Text string
ASCII "KERNEL32.DLL"
ASCII "USER32.DLL"
ASCII "ADVAPI32.DLL"
ASCII "WSOCK32.DLL"
ASCII "NTDLL.DLL"
(Initial CPU selection)
ASCII "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
ASCII "BatSrv"
ASCII "tmx"
ASCII "hxxx://5sec.biz/report/sox.php"
ASCII "%s %d"
ASCII "sysc
ASCII "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
ASCII "BatSrv"
ASCII "SYSTEM\CurrentControlSet\Services\Tcpip"
ASCII "TcpNumConnections
ASCII "5sec.biz"
ASCII "hxxx://%s/report.php?ip=%u.%u.%u.%u&p=%lu&uid=%012lu&aid=%s&ver=%s&con=%s&speed=%d"
ASCII "tmx"
ASCII "tmx"
ASCII "hxxx://www.microsoft.com"
ASCII "hxxx://5sec.biz:80/report/upd1.exe"
ASCII "hxxx://5sec.biz:80/report/upd1.txt"
ASCII "hxxx://5sec.info:80/report/upd1.exe"
ASCII "hxxx://5sec.info:80/report/upd1.txt"
ASCII "tmx"
ASCII "netsh firewall set allowedprogram "%s" enable"
ASCII "MZ"
ASCII "MZ"


Names in unpack_f
Address Name Comment
0040141D USER32.CharLowerBuffA
00401143 kernel32.CloseHandle
00401147 kernel32.CopyFileA
0040114B kernel32.CreateFileA
0040114F kernel32.CreateProcessA
00401153 kernel32.CreateToolhelp32Snapshot
00401157 kernel32.DeleteFileA
0040115B kernel32.ExitProcess
0040115F kernel32.GetComputerNameA
00401163 kernel32.GetFileSize
004014C6 WS2_32.gethostbyname
004014CA WS2_32.gethostname
00401167 kernel32.GetModuleFileNameA
0040116B kernel32.GetProcAddress
0040116F kernel32.GetSystemDirectoryA
00401173 kernel32.GetSystemTime
00401177 kernel32.GetTempFileNameA
0040117B kernel32.GetTempPathA
0040117F kernel32.GetThreadContext
00401183 kernel32.GetTickCount
00401187 kernel32.GetVolumeInformationA
0040118B kernel32.GetWindowsDirectoryA
0040118F kernel32.LoadLibraryA
004011C7 kernel32.lstrcat
004011CB kernel32.lstrcpy
00401ACB <ModuleEntryPoint>
00401193 kernel32.OpenProcess
00401197 kernel32.Process32First
0040119B kernel32.Process32Next
0040119F kernel32.ReadFile
0040145A ADVAPI32.RegCloseKey
0040145E ADVAPI32.RegCreateKeyExA
00401462 ADVAPI32.RegQueryValueExA
00401466 ADVAPI32.RegSetValueExA
004011A3 kernel32.ResumeThread
004011A7 kernel32.SetThreadContext
004011AB kernel32.Sleep
00401505 ntdll.strstr
004011AF kernel32.TerminateProcess
004011B3 kernel32.VirtualAllocEx
004011B7 kernel32.WaitForSingleObject
004011BB kernel32.WinExec
004011BF kernel32.WriteFile
004011C3 kernel32.WriteProcessMemory
004014C2 WS2_32.WSAStartup
00401421 USER32.wsprintfA



Executable modules
Base Name Path
00400000 unpack_f C:\Documents and Settings\admi\Desktop\unpack_fsg_malware.exe
71AA0000 WS2HELP C:\WINDOWS\system32\WS2HELP.dll
71AB0000 WS2_32 C:\WINDOWS\system32\WS2_32.dll
77C10000 msvcrt C:\WINDOWS\system32\msvcrt.dll
77DD0000 ADVAPI32 C:\WINDOWS\system32\ADVAPI32.DLL
77E70000 RPCRT4 C:\WINDOWS\system32\RPCRT4.dll
77F10000 GDI32 C:\WINDOWS\system32\GDI32.dll
77FE0000 Secur32 C:\WINDOWS\system32\Secur32.dll
7C800000 kernel32 C:\WINDOWS\system32\kernel32.dll
7C900000 ntdll C:\WINDOWS\system32\ntdll.dll
7E410000 USER32 C:\WINDOWS\system32\USER32.DLL




DANGER MALWARE LOCKSKY WRM

i attached the unpacked exe
password malware

live_dont_exist
November 13th, 2011, 08:36
Thanks blabberer.

It's strange that you're not seeing the same problem. My OEP after unpacking is 00401ACB. Please have a look at those screenshots in the attachment earlier. Those exactly represent what I saw before unpacking, after unpacking and after decryption.

I'll take a look at your attachment now.

Arvind

EDIT: I looked at your entry point and its the same, but with all the DLL's. After I unpack [OllyDump, Rebuild Imports checked] I get only kernel32.dll and ntdll.dll.

esther
November 13th, 2011, 11:27
Hi,
The IAT is redirected,you have to set breakpoint on memory access where you think the api is
eg:00401147 kernel32.CopyFileA

imprec causes errors coz your need to put your RVA and get imports

live_dont_exist
November 13th, 2011, 13:20
Thanks Esther.

The problem here though is that for me the DLL which contains the API does not seem to get loaded at all in the first place. So, that means the API will not be in memory at all..rt?When blabberer is loading up the EXE after dumping though.. he can clearly see all the DLLs and the problem no longer is a problem.

With imprec what I understood is:

a) Get OEP and try and search
b) If you find something great, see if you get any invalid entries after "Get Imports" and then remove those
c) Use the RVA and size correctly [First API in first DLL TO Last API in Last DLL] to get all imports
d) Then Fix Dump

But here that DLL itself is never loaded for some reason. Why I cannot understand, specially when I dumped it just like blabberer did and got the same OEP

Thanks
Arvind

blabberer
November 13th, 2011, 13:55
you need to dump after decryption routine which is at same oep dump after the address 401acb is hit the second time

here is a paste of the unpacking process

simply automatic unpacking using trace over twice and one condition will take about 3 to 4 minutes

Code:


Log data
Address Message
7C90D040 Breakpoint at ntdll.ZwContinue
7C8106F5 Breakpoint at kernel32.BaseProcessStartThunk
7C817064 Breakpoint at <kernel32.Kernel32!BaseProcessStart+0x20> (BaseProcessStart+20)
00400154 Program entry point

[esp] = 7c817067
setting condition [esp] == 0x7c817067 && eip == 00401acb and hitting trace over ctrl+f12

7E410000 Module C:\WINDOWS\system32\USER32.DLL
77F10000 Module C:\WINDOWS\system32\GDI32.dll
77DD0000 Module C:\WINDOWS\system32\ADVAPI32.DLL
77E70000 Module C:\WINDOWS\system32\RPCRT4.dll
77FE0000 Module C:\WINDOWS\system32\Secur32.dll
71AD0000 Module C:\WINDOWS\system32\WSOCK32.DLL
71AB0000 Module C:\WINDOWS\system32\WS2_32.dll
77C10000 Module C:\WINDOWS\system32\msvcrt.dll

00401ACB Conditional pause: [esp] == 0x7c817067 && eip == 00401acb
"no of commands run till now on ctrl+f8 is 72081
"this is prelim we need to dump after second so lets hit ctrl+f12 again"
00401ACB Conditional pause: [esp] == 0x7c817067 && eip == 00401acb
"no of commands run till now on ctrl+f8 is 79830"
"hit ollydump and dump"


OllyDump -- Start "JMP [Thunk]"(0x25FF) and "CALL [Thunk]"(0x15FF) search
00401AE3 call[Thunk] found on 00401AE3 Thunk:00401167

snip ***************************************************

OllyDump -- Resolve Forwarder
OllyDump -- Exception in Resolve Forwarder !!
OllyDump -- Import Table
00401143 DLL:kernel32.dll FirstThunkRVA:1143
DLL Name Address Ordinal API Name
00401143 kernel32.dll 7C809BD7 0032 CloseHandle
00401147 kernel32.dll 7C8286D6 0040 CopyFileA
0040114B kernel32.dll 7C801A28 0050 CreateFileA
0040114F kernel32.dll 7C80236B 0063 CreateProcessA
00401153 kernel32.dll 7C865B1F 0070 CreateToolhelp32Snapshot
00401157 kernel32.dll 7C831EC5 0082 DeleteFileA
0040115B kernel32.dll 7C81CAFA 00B7 ExitProcess
0040115F kernel32.dll 7C82168C 010E GetComputerNameA
00401163 kernel32.dll 7C810B07 015C GetFileSize
00401167 kernel32.dll 7C80B55F 0175 GetModuleFileNameA
0040116B kernel32.dll 7C80AE30 0199 GetProcAddress
0040116F kernel32.dll 7C814F7A 01BA GetSystemDirectoryA
00401173 kernel32.dll 7C80176F 01BF GetSystemTime
00401177 kernel32.dll 7C861807 01CA GetTempFileNameA
0040117B kernel32.dll 7C835DE2 01CC GetTempPathA
0040117F kernel32.dll 7C839725 01CE GetThreadContext
00401183 kernel32.dll 7C80932E 01D5 GetTickCount
00401187 kernel32.dll 7C821B8D 01E1 GetVolumeInformationA
0040118B kernel32.dll 7C82134B 01E9 GetWindowsDirectoryA
0040118F kernel32.dll 7C801D7B 0245 LoadLibraryA
00401193 kernel32.dll 7C8309D1 0278 OpenProcess
00401197 kernel32.dll 7C864DF5 0288 Process32First
0040119B kernel32.dll 7C864F68 028A Process32Next
0040119F kernel32.dll 7C801812 02A7 ReadFile
004011A3 kernel32.dll 7C83290F 02C3 ResumeThread
004011A7 kernel32.dll 7C863AA9 032E SetThreadContext
004011AB kernel32.dll 7C802446 0343 Sleep
004011AF kernel32.dll 7C801E1A 034B TerminateProcess
004011B3 kernel32.dll 7C809B02 0370 VirtualAllocEx
004011B7 kernel32.dll 7C802530 037F WaitForSingleObject
004011BB kernel32.dll 7C8623AD 0384 WinExec
004011BF kernel32.dll 7C810E17 0390 WriteFile
004011C3 kernel32.dll 7C802213 0399 WriteProcessMemory
004011C7 kernel32.dll 7C834D59 03A8 lstrcat
004011CB kernel32.dll 7C80BE91 03B1 lstrcpy

0040141D DLL:USER32.DLL FirstThunkRVA:141D
DLL Name Address Ordinal API Name
0040141D USER32.DLL 7E428845 0028 CharLowerBuffA
00401421 USER32.DLL 7E41A8AD 02D9 wsprintfA

0040145A DLL:ADVAPI32.DLL FirstThunkRVA:145A
DLL Name Address Ordinal API Name
0040145A ADVAPI32.DLL 77DD6C17 01CB RegCloseKey
0040145E ADVAPI32.DLL 77DDE9E4 01CF RegCreateKeyExA
00401462 ADVAPI32.DLL 77DD7AAB 01EF RegQueryValueExA
00401466 ADVAPI32.DLL 77DDEAD7 01FC RegSetValueExA

004014C2 DLL:WS2_32.dll FirstThunkRVA:14C2
DLL Name Address Ordinal API Name
004014C2 WS2_32.dll 71AB6A55 0073 WSAStartup
004014C6 WS2_32.dll 71AB5355 0034 gethostbyname
004014CA WS2_32.dll 71AB5449 0039 gethostname

00401505 DLL:ntdll.dll FirstThunkRVA:1505
DLL Name Address Ordinal API Name
00401505 ntdll.dll 7C90E75E 0508 strstr
00401509 FFFFFFFF FFFF

OllyDump -- Calculating New File Size...
New Import Section Size:600 New File Size:8600
OllyDump -- Making New Import Table...
OllyDump -- Dump and Rebuild Finish!!


File 'C:\Documents and Settings\admi\Desktop\arvind_unpack.exe'
New process with ID 000000A8 created

7C90D040 Breakpoint at ntdll.ZwContinue
7C8106F5 Breakpoint at kernel32.BaseProcessStartThunk
7C817064 Breakpoint at <kernel32.Kernel32!BaseProcessStart+0x20> (BaseProcessStart+20)
00401ACB Program entry point
Analysing arvind_u
41 fuzzy procedures
83 calls to known, 4 calls to guessed functions
6 loops, 1 switches or cascaded if's


live_dont_exist
November 14th, 2011, 01:48
I tried setting a breakpoint on 401ACB but that never ever got triggered . Even a simple breakpoint like eip==00401acb without the [esp] value did not get triggered. The syntax was correct as I tried it on some other location and it seemed to work.

Then I just set a simple breakpoint not conditional (F2 only) on 00401acb and even that did not get triggered. Is this because the instructions at that address are modified by the decryption routine?

Then I set a Hardware breakpoint in 401acb and that got triggered; I dumped it after decryption and all was okay. I could see all the DLLs imported, just like on your machine.

Then I removed all breakpoints and did an F8 like before and again...everything was okay !!. Now I am not sure why the problem came up in the first place at all

Anyway I think it is solved. But I only have 2 more new questions now:

---- Why did the conditional breakpoint not work? Is it because the code got overwritten? Is setting Hardware breakpoints the only way to go

---- The value of [esp] in your example and in mine is different. Is that ok? My assumption here is that I am supposed to set the conditional breakpoint ON 401acb - Go to 401acb - Shift+F2 - [esp] == 0x7c817067 && eip == 00401acb . At this point my value of [esp] is different. If we are both running the exact same code, why is [esp] different? Is it because of different hardware we are using?

Thank You very much

Arvind

live_dont_exist
November 14th, 2011, 02:16
I read a very nice article about why Software breakpoints would not work here and which clarified a few things for me. Here is the link to that article - 3 part series:

http://www.nynaeve.net/?p=80
http://www.nynaeve.net/?p=81
http://www.nynaeve.net/?p=83

Arvind

blabberer
November 14th, 2011, 16:16
ken johnson aka skywing's blogs are imported here too

value as in speciific address of [esp] can be different due to ASLR

software breakpoints normally do not work on self modifying codes and they normally tend to screw up the decryption too

F8 also screws up decryption because f8 internally sets a temporary one shot breakpoint as illustrated below

Code:


f8screwup:\>dir /b
f8screwup.c

f8screwup:\>type f8screwup.c
#include <stdio.h>
int MagicCall (void);
int magic = 0;
int main (void){
printf("try stepping over The MagicCalls and you will see the problem\n"
);
MagicCall();
if (1== magic)
{
printf("bad babe you cant step over MagicCalls\n" ;
return 1;
}
printf ("good boy you didnt step over MagicCalls\n";
return 0;
}
int MagicCall (void){
__asm
{
mov eax , dword ptr ss:[esp+4]
movzx eax,byte ptr ds:[eax]
cmp al ,0xcc
jnz boom
mov magic ,1
boom:
}
return 0;
}
f8screwup:\>cl /nologo f8screwup.c
f8screwup.c

f8screwup:\>dir /b
f8screwup.c
f8screwup.exe
f8screwup.obj

f8screwup:\>f8screwup.exe
try stepping over The MagicCalls and you will see the problem
good boy you didnt step over MagicCalls

f8screwup:\>cdb -c "bp 0x401010;g;p;g;q" f8screwup.exe

Microsoft (R) Windows Debugger Version 6.12.0002.633 X86
Copyright (c) Microsoft Corporation. All rights reserved.

CommandLine: f8screwup.exe
Symbol search path is: SRV*F:\symbols*http://msdl.microsoft.com/download/symbols

Executable search path is:
ModLoad: 00400000 0040f000 image00400000
ModLoad: 7c900000 7c9b2000 ntdll.dll
ModLoad: 7c800000 7c8f6000 C:\WINDOWS\system32\kernel32.dll
ModLoad: 64d00000 64d34000 C:\Program Files\Alwil Software\Avast5\snxhk.dll
(c88.c7c): Break instruction exception - code 80000003 (first chance)
eax=00261eb4 ebx=7ffde000 ecx=00000005 edx=00000020 esi=00261f48 edi=00261eb4
eip=7c90120e esp=0013fb20 ebp=0013fc94 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
ntdll!DbgBreakPoint:
7c90120e cc int 3
0:000> cdb: Reading initial command 'bp 0x401010;g;p;g;q'
ModLoad: 5cb70000 5cb96000 C:\WINDOWS\system32\ShimEng.dll
try stepping over The MagicCalls and you will see the problem
Breakpoint 0 hit
bad babe you cant step over MagicCalls
quit:

f8screwup:\>cdb -c "bp 0x401010;g;t;g;q" f8screwup.exe

Microsoft (R) Windows Debugger Version 6.12.0002.633 X86
Copyright (c) Microsoft Corporation. All rights reserved.

CommandLine: f8screwup.exe
Symbol search path is: SRV*F:\symbols*http://msdl.microsoft.com/download/symbols

Executable search path is:
ModLoad: 00400000 0040f000 image00400000
ModLoad: 7c900000 7c9b2000 ntdll.dll
ModLoad: 7c800000 7c8f6000 C:\WINDOWS\system32\kernel32.dll
ModLoad: 64d00000 64d34000 C:\Program Files\Alwil Software\Avast5\snxhk.dll
(eac.e14): Break instruction exception - code 80000003 (first chance)
eax=00261eb4 ebx=7ffdf000 ecx=00000005 edx=00000020 esi=00261f48 edi=00261eb4
eip=7c90120e esp=0013fb20 ebp=0013fc94 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
ntdll!DbgBreakPoint:
7c90120e cc int 3
0:000> cdb: Reading initial command 'bp 0x401010;g;t;g;q'
ModLoad: 5cb70000 5cb96000 C:\WINDOWS\system32\ShimEng.dll
try stepping over The MagicCalls and you will see the problem
Breakpoint 0 hit
good boy you didnt step over MagicCalls
quit:

f8screwup:\>



p = f8 in ollydbg t = f7 in ollydbg


i said i used set condition that is ctrl+t or view->set condition condition is true checkbox and then i used run trace (it is a single line complex condition)
it checks for eip == 0x401acb and also checks if [esp = ntdll!BaseProcessStart+0x20) and breaks only if both conditions are met

i did not use conditional breakpoints (neither shift+f2 nor shift +f4)

using hardware breakpoints is always the best way
the problem with hardware breakpoints are they are limited only 4 break points can be set in one debugging session
and some cleverer malwares clear the dr7 debug register to erase the hardware breakpoints too
so they may also not trigger in few cases

live_dont_exist
November 14th, 2011, 23:49
That's interesting. F8 also setting a temp breakpoint :-o .

If I understand your code in the first case - you set a breakpoint, started run trace with F8 - this triggered badboy because of F8's internal breakpoint mechanism as you mention. In the second case you did the same thing but with F7; in this case the breakpoint was never triggered. That's strange coz the debugger will pass over the breakpoint with both F7 and F8; so why the difference in behavior for F8? But maybe that is too much for me at this point

In my case, when I set no breakpoints and F8'd throughout; when I passed the self modified code, it still went through. However as soon as I hit Ctrl+A , Olly analyzed the code and changed everything [Maybe this is normal]

Can I set that one line condition someway in Olly?

Thanks
Arvind

live_dont_exist
November 16th, 2011, 09:07
I think I got how you can set the condition for Trace. In Olly you click on Debug - Set Condition and set the values accordingly. Then you can trace over or trace into the code. Haven't yet tested this though so dont flame me . I'll edit this post when I do test it out completely; just thought I'd put this out though.

Arvind

blabberer
November 16th, 2011, 09:36
i was going to quote with some sarcasm but since you posted a reply ill cut out the sarcasm

do test it and ask if you find any problems

Quote:


without sarcasm

i said i used set condition that is ctrl+t or view->set condition condition is true checkbox and then i used run trace (it is a single line complex condition)
it checks for eip == 0x401acb and also checks if [esp = ntdll!BaseProcessStart+0x20) and breaks only if both conditions are met

Conditional pause: [esp] == 0x7c817067 && eip == 00401acb


live_dont_exist
November 16th, 2011, 10:27
Ooopss... my bad .. glad I got the reply out before the sarcasm... I was actually gonna reply later tonight but since it was a short post ... thought I would do it .. good I did....

I will surely test and come back with an update.

Thanks for all the help

Arvind