Le Packing (for newbies) Part 2

Rappelons nous le dernier post. On était arrivé à la conclusion que notre exécutable était packé (On a d’ailleur a cette occasion appris ce que c’était), mais on patinait dans la choucroute pour le dépacker de façons automatique. On va donc devoir sortir tout l’attirail pour tenter de le dépacker, J’ai nommé IDA pour désassembler et Ollydgb pour débugger et le vénérable LORD_PE pour dumper le processus depuis la ram. Pour une somme modique on peut tout faire avec IDA sur une vaste gamme de systèmes avec des plugins comme IDA_Dumper. Ha l’argent, c’est probablement la raison pour laquelle tout le monde se tourne vers OllyDbg (Enfin pour l’instant en 32Bits uniquement). Il nous faudra aussi d’autres petits tools. Nous y reviendrons plus tard.

Pour s’échauffer on va reprendre notre Hello World packé sous UPX de la partie 1 de cet article et on va se le dé-packer à la main.

Le cas simple “find the Jump”

L’idée est la suivante; Que va faire un packer simple, il va décompresser/déobfusquer le code réel, puis il vas sauter dedans pour l’exécuter. La première méthode dans le cas d’un packer pour newbies est de trouver oû est ce saut, d’y poser un breakpoint, de laisser faire le programme dépackant et quand on arrive à notre breakpoint on dumpe le programme et on crée un nouvel exécutable.

Ouvrons notre hello world upx dans IDA, dés-fois que cela serait simple. Et heureusement oui, UPX c’est bien pour l’apprentissage. Au premier abords ca fait peur. En y regardant plus près, il n’y a qu’une seule fonction. Et on trouve facilement le saut car IDA nous informe qu’au dela de ce saut, le il n’y a pas de programme exécutable (sp-analysis failed). Il n’y a pas encore de programme car le décompresseur n’a pas été lancé. Là c’est facile ida vois bien qu’il n’y a pas de code derrière le “JMP”, mais cela peut être moins évident avec un saut de type “call registre” ou un “ret”.

Upx in IDA

On se met sur la ligne de saut, on appuie sur “space” pour avoir le désassembler en vue liste et on note l’adresse du saut (Ici 0x004076EB).

Ida Jump Upx

Ensuite on ouvre OllyDbg, on charge l’exécutable. On met un point d’arrêt (F2) au même endroit.

Olly Dbg Breakpoint

Voila, le piège est en place, ne reste plus qu’a lancer. Quand Ollydbg rend la main on est devant notre saut, on step d’une instruction (F7) et on se retrouve devant notre code dépacké. On note la valeur d’Eip, ici 0x00401130, c’est là que le vrai programme commence.

Upx Jump address

Il ne reste qu’a dumper le programme, Pour cela on lance notre LORD_PE (Nota il y a plein de soft qui font la même chose, même des plugins OllyDbg le font (ex PE_Dumper) , choisis tes armes camarade).

On sélectionne notre exécutable et on le dump “Full”.

Lord_PE Dump

Là notre LORD_PE fait un truc étonnant dont il faut avoir conscience. Il “Rebuild Import Table”

Lord_PE Export

Apparté, Rebuilding de l’IAT : Dans un executable PE, l’IAT de son nom complet Import Adress Table est un tableau de correspondances pour les fonctions importées (Un appel a une fonction de Kernel32.dll par exemple). Elle contient ce qui doit être importé ainsi que le nom des dites DLL (Pour les amis des ELF on peut considéré cela comme une genre de GOT). C’est indépendant de la version de windows, au démarrage la correspondance fonction vers l’adresse de la lib est remise en place. En plus de cela, notre Packer a nettoyé cette IAT avec les fonction que seul lui utilise, une fois dépacké, il faut donc remettre l’IAT en ordre. A la main, on oublie, mais avec le bon tools c’est simple.

Pour plus d’informations sur l’IAT je vous encourage à lire ce lien.

Mais ce n’est pas tout ! Il faut encore changer l’EP, l’Entry Point. C’est a dire l’emplacement en mémoire où va démarrer le programme. Il faut que l’on démarre là où on a finis le dépacking (rapellez vous l’addresse 0x00401130 que l’on a noté ).

On reprend LordPE, on prend l’option PE Editor, on édite l’exécutable que l’on vient de dumper. On change l’Entry Point. La base étant 0x0040000 il suffit de mettre 0x1130 dans la case.

Entry Point

Voila c’est finis, on a retrouvé notre executable “décompréssé”, Avec son code et ses strings en clair.

$ strings hello-upx-dumped.exe  | grep hello
hello World !

Malheureusement c’est rarement aussi facile qu’avec UPX.

La méthode ‘Regarde le Tas’

Si le packers commence par sauver la valeur de la pile ou fait un gros PUSHA (haaa ce formidable 32 Bits, il va me manquer). On peut aussi penser à mettre un break point hardware sur la position mémoire de la pile. En se disant, arrivé dans notre code packé, la pile sera revenue à la position initiale. Upx fait aussi comme cela, il est nickel comme exemple cet UPX. Pour faire ceci avec OllyDbg je lance mon programme, je passe le PUSHAD (f7) en step by step, je vais sur la valeur du registre ESP et je l’affiche dans le dump.

pushaddepack

Je selection le word qui se trouve à l’emplacement de ma pile, et j’insère un breakpoint hardware en R/W.

Hardware Breakpoint

Je lance le programme… Et hoo miracle il rend la main dans la fameuse boucle (que l’on connais maintenant) et qui va sauter sur le programme dépacké. il suffit de faire un peu pas à pas jusqu’au saut et on se retrouve là aussi en 0x00401130

stack jump codeA partir de là, Dump, IAT et EP..comme précédemment et c’est bon.

La technique de siY0ug

Mais dans la vraie vie c’est pas toujours aussi rose, même s’il n’y a pas d’anti debugger, on peut errer dans le code pendant des jours à chercher le saut. Par exemple notre facture.exe (Hash 17832c9a78b36c8a3133e2c2e24ebc3b9896763a chez Malware.lu). Il contient 131 fonctions, du code long comme le bras avec utilisation du co-processeur arithmétique, des champs complet de calls dans tous les sens, pas de pusha au début (par contre de la réservation de heap).. Bref… Glups.

facture

Nous voici acculé. Pas de dépackeur tout fait, Trop alambiqué dans IDA. C’est à ce moment là que l’on pleure auprès d’un compagnon de café qui lâche la méthode suivante. Dixit le gaillard (Et c’est pas une tanche coté déssossage) on arrive à dépacker 3/4 des packeur de PE avec du malware dedans. L’idée est la suivante;

On va laisser le malware faire son un-package et on va breaker quand monsieur va faire un appel bien sentis à kernel32. Généralement quand il est en train d’injecter son code dans un autre process (c’est typique pour un malware voir ceci). Actuellement on a vu des packer qui se décompressent dans le même segment mémoire, mais certain se prennent du heap et y sortent carrément un autre executable.

Bon comme çà, ça parait simple, mais ne déconnez pas, faite ceci dans un environnement clos. Une bonne grosse sandbox; Cuckoo, Vmware, au pire un poste dédié.

Si vous ratez le breakpoint, vous êtes poncé, si le dépackeur contient aussi une saloperie,  vous êtes poncé., Si le malware s’attache pas à un process comme vous le pensez, vous êtes poncé; Bref à chaque mauvaise manip, vous êtes poncé.

Reprenons Ollydbg. On ouvre l’exécutable, on demande la fenêtre “Executable Modules” (Alt+E) on sélectionne Kernel32, on fait “show names” (ctrl+N). Devant nous apparaît la fenêtre avec la liste de toutes les fonctions de Kernel32.dll

show names

On cherche “WriteProcessMemory” (Il suffit de taper les premières lettres) et on met en place un breakpoint (F2).

writeprocessmemory

Ensuite , confiant on lance le programme. Quand celui ci rend la main juste avant la fonction. Dans la stack on retrouve les paramètre d’appel à cette fonction, et si on fait “Follow in dump” de l’addresse du “Buffer” on se rend compte que dans ce buffer on est en présence d’un exécutable complet.

executable depacked

Là c’est différent, c’est un programme complet qu’il faudra extraire du dump mémoire. Soyez heureux, pas de IAT et d’EP à tripoter).

Si ça ne va pas avec cette fonction là … On peut essayer les fonctions suivantes

Maintenant extrayons notre exécutable de la mémoire. Sur le dump mémoire sous OllyDbg on fait Bouton droit de la souris => Backup => Create Backup. on se retrouve avec un dump mémoire complet de ce processus. Il suffit de trouver ou commence l’exécutable, et découper. et pour cela, on remercie Zbikowski !!! on cherche les MZ

$ grep -boa MZ backup_00140000.bin.bin 
21792:MZ
27676:MZ
53930:MZ
114271:MZ
116204:MZ
197816:MZ
308269:MZ

Pas de bol il y en a un ou deux.. on les essaye plus précis, on a vu dans le dump mémoire que c’était MZ suivis de 0x90 0x00.

$ grep -boa MZ$'\x90\x00' backup_00140000.bin.bin 
21792:MZ?
197816:MZ?

Ouf plus que 2 à essayer, Rappelons nous l’original packé était :

$ peentro.py facture.exe.malv 
Section	Entropy	Bytes	Size	MD5					Remark
.code	5.65	6	8503	6d7c8f47c89843bafb8d8a0912730242	
.text	6.49	7	9716	5e70fa9623805d69b6e548873c23d37f	
.rdata	1.75	2	188	96fdc428b50e1fa15bc8ce78d17a0525	
.data	5.29	6	2796	cd00c1734804fcf8f776f8ce3431b129	
.rsrc	2.94	3	4444	0b5ae9b8bfbc2ecfcb22c9578e800439

Extrayons le premier.  (Note : la valeur pour le tail est +1 par rapport au grep.)

$ tail -c+21793 backup_00140000.bin.bin > facture1.unpacked
$ peentro.py facture1.unpacked 
Section	Entropy	Bytes	Size	MD5					Remark
.code	5.65	6	8503	6d7c8f47c89843bafb8d8a0912730242	
.text	6.49	7	9716	5e70fa9623805d69b6e548873c23d37f	
.rdata	1.75	2	188	96fdc428b50e1fa15bc8ce78d17a0525	
.data	5.29	6	2796	cd00c1734804fcf8f776f8ce3431b129	
.rsrc	2.94	3	4444	0b5ae9b8bfbc2ecfcb22c9578e800439

Zut, on est retombé sur l’original.. Allons y pour le second candidat :

$ tail -c+197817 backup_00140000.bin.bin > facture2.unpacked
$ peentro.py facture2.unpacked 
Section	Entropy	Bytes	Size	MD5					Remark
.text	6.72	7	134836	97f0523f3fa408480c81e763935aedc1	
.data	1.58	2	8276	841bea2427018da084fc8db606a058f8	
.reloc	5.67	6	5778	d251d79e05658d968ee468f36f562f3e

Bingo un autre executable !  Allons y.. tentons un strings, somme nous victorieux ?? (Le grep étrange c’est pour n’attraper que les digram les plus utilisé en anglais, ca évite pas mal de strings random)

$ strings -10 facture2.unpacked | egrep 'th|he|in|er|an|re|nd|at'
Content-Length
Authorization
Transfer-Encoding
Accept-Encoding
If-Modified-Since
userenv.dll
CreateEnvironmentBlock
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1)
Content-Type: application/x-www-form-urlencoded
ObtainUserAgentString
cabinet.dll
FCIFlushCabinet
bepfLvtcklre
v6!!2>6-7<=)+,.an"*&%/--gulh!y
GdipCreateBitmapFromHBITMAP
GdipGetImageEncodersSize
GdipGetImageEncoders
GdipSaveImageToStream
CreateStreamOnHGlobal
CreateCompatibleDC
CreateCompatibleBitmap
GetProcAddress
NtCreateThread
NtCreateUserProcess
NtQueryInformationProcess
RtlUserThreadStart
LdrGetDllHandle
GetModuleHandleW
GetPrivateProfileStringW
CreateFileW
FlushFileBuffers
GetPrivateProfileIntW
GetProcAddress
EnterCriticalSection
CloseHandle
WaitForSingleObject
FileTimeToDosDateTime
CreateMutexW
FindFirstFileW
SetEndOfFile
FreeLibrary
CreateProcessW
SetFilePointerEx
CreateDirectoryW
GetCurrentThread
VirtualFree
VirtualQueryEx
Thread32First
VirtualFreeEx
HeapCreate
Thread32Next
GetTimeZoneInformation
GetTempPathW
RemoveDirectoryW
FindNextFileW
CreateToolhelp32Snapshot
GetVolumeNameForVolumeMountPointW
GetFileInformationByHandle
CreateThread
ExpandEnvironmentStringsW
SetThreadPriority
GetCurrentThreadId
CreateEventW
GetThreadContext
SetThreadContext
CreateFileMappingW
CreateRemoteThread
GetUserDefaultUILanguage
TerminateProcess
GetCommandLineW
GetComputerNameW
GetVersionExW
DuplicateHandle
GetCurrentProcessId
GetNativeSystemInfo
DispatchMessageW
SendMessageTimeoutW
SetWindowLongW
CharUpperW
CharLowerA
GetWindowLongW
TranslateMessage
WindowFromPoint
GetTopWindow
ExitWindowsEx
CharLowerBuffA
OpenWindowStationW
GetUserObjectInformationW
SetThreadDesktop
GetProcessWindowStation
CreateWindowStationW
CloseWindowStation
GetThreadDesktop
SetProcessWindowStation
CreateDesktopW
RegisterClassA
DefWindowProcW
CallWindowProcW
CallWindowProcA
RegisterClassW
ReleaseCapture
DefWindowProcA
GetClipboardData
RegisterClassExW
GetCapture
GetUpdateRect
BeginPaint
SetCapture
GetWindowDC
RegisterClassExA
GetUpdateRgn
GetShellWindow
GetWindowThreadProcessId
SendMessageW
PostThreadMessageW
GetMenuState
SystemParametersInfoW
MenuItemFromPoint
SetKeyboardState
RegisterWindowMessageW
GetKeyboardState
MapWindowPoints
SetWindowPos
GetWindowInfo
GetWindowRect
PrintWindow
IntersectRect
CharLowerW
GetSidSubAuthority
CryptAcquireContextW
OpenThreadToken
GetSidSubAuthorityCount
GetTokenInformation
RegCreateKeyExW
RegQueryValueExW
CreateProcessAsUserW
CryptCreateHash
ConvertStringSecurityDescriptorToSecurityDescriptorW
CryptHashData
InitiateSystemShutdownExW
GetLengthSid
ConvertSidToStringSidW
wvnsprintfW
PathIsDirectoryW
PathFindFileNameW
PathRemoveFileSpecW
PathAddBackslashW
PathSkipRootW
PathCombineW
PathAddExtensionW
PathUnquoteSpacesW
PathRemoveBackslashW
PathMatchSpecW
wvnsprintfA
PathIsURLW
PathQuoteSpacesW
PathRenameExtensionW
SHGetFolderPathW
ShellExecuteW
CommandLineToArgvW
GetUserNameExW
CoCreateInstance
CoUninitialize
CLSIDFromString
StringFromGUID2
CreateCompatibleBitmap
CreateDIBSection
CreateCompatibleDC
freeaddrinfo
getaddrinfo
WSAAddressToStringW
CryptUnprotectData
PFXImportCertStore
CertDeleteCertificateFromStore
CertOpenSystemStoreW
CertCloseStore
CertEnumCertificatesInStore
CertDuplicateCertificateContext
PFXExportCertStoreEx
HttpQueryInfoA
InternetConnectA
InternetQueryOptionW
InternetCrackUrlA
InternetReadFile
InternetSetOptionA
HttpSendRequestA
InternetOpenA
InternetCloseHandle
InternetQueryOptionA
HttpSendRequestExA
HttpSendRequestExW
InternetQueryDataAvailable
InternetReadFileExA
HttpSendRequestW
GetUrlCacheEntryInfoW
InternetSetStatusCallbackW
HttpAddRequestHeadersW
HttpAddRequestHeadersA
NetUserGetInfo
NetApiBufferFree
NetUserEnum

Et en unicode, y a t’il des strings ?

$ strings -el -10 facture2.unpacked 
kernel32.dll
S:(ML;;NRNWNX;;;LW)
SeSecurityPrivilege
S:(ML;CIOI;NRNWNX;;;LW)
SeShutdownPrivilege
SeTcbPrivilege
SOFTWARE\Microsoft
cGlobal\%08X%08X%08X
SysListView32
CiceroUIWndFrame
ConsoleWindowClass

Pas mal, quel sont maintenant les dll utilisées ?

$ objdump -x facture2.unpacked | grep "DLL Name"
DLL Name: KERNEL32.dll
DLL Name: USER32.dll
DLL Name: ADVAPI32.dll
DLL Name: SHLWAPI.dll
DLL Name: SHELL32.dll
DLL Name: Secur32.dll
DLL Name: ole32.dll
DLL Name: GDI32.dll
DLL Name: WS2_32.dll
DLL Name: CRYPT32.dll
DLL Name: WININET.dll
DLL Name: OLEAUT32.dll
DLL Name: NETAPI32.dll

Ho le support du réseau est arrivé ;) et plein d’autres DLLs qui laissent a penser que le malware est bien juteux

Et bien voila, c’est une victoire il semblerai la bête soit dé-packée. Ne reste plus qu’a l’analyser… Une broutille ;)

Mais ca c’est pour une autre fois.

This entry was posted in Reverse and tagged , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

AlphaOmega Captcha Classica  –  Enter Security Code