binee icon indicating copy to clipboard operation
binee copied to clipboard

Bugs found while testing on malware unusual packers + Hooks implemented

Open mmn3mm opened this issue 4 years ago • 0 comments

Issue 1: Parsing Resources Functions related to resource section(eg: LoadStringA) failed in binee when I set a partial hook, so when I looked into it I and started analyzing I found that for the functions to work, they require DllMain for dlls to be run, when I enabled the option in binee there is much more headache to deal with, that's because most of DllMains require fields from undocumented windows structures(PEB). I did some research but I found it will probably take lots of time to handle. I also thought parsing all resources might come in handy later upon analysis of parts in the binary or feature extraction. It wasn't a very easy process since its not really well documented, but I successfully parsed it and have an article explaining how I did it. Link: https://github.com/mmn3mm/peresources/blob/master/README.md

To reproduce the issue:
    I added a test binary in the tests folder to check the behavior.

Issue 2: Forwarded exports Binee didn't take into consideration the forwarded exports at all, I don't have to explain how this works as it is explained here: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#export-address-table. As always I tried to mimic the windows behavior as much as I can. I always use ReactOs's (https://reactos.org/) project as a reference as its very close to windows implementation.I implemented it here so it can be recursive just like windows. The problem came out first due to the method binee uses to hook functions, it depends on EAT hooking, but since in forwarded export the address is pointing to a string which specifies the function it is pointing to, binee hooked wrong location and didn't resolve it correctly and executed the actual string as if it were the start of the actual function. I also added the functionality/option to parse and print this.

To reproduce the issue:
        SHA256(sample)= 7bf87e4afdfc2a385a2a3d045fffed45ad0f56d7ca4ebe5dad03e18f376e9f4d
        SHA1(sample)= f11e5edb86148f31ccae18bc7d3029f500298e7c
        MD5(sample)= 0695c74d1f11b201eab7dd5b31808bc2
    I can provide the sample if requested but it can be found easily by searching, this is a malware that calls the "DeleteCriticalSection" function in kernel32.dll, but this function is in fact just a forwarded export to RtlDeleteCriticalSection in ntdll.
    To test parsing, find any version of kernel32.dll and start binee with this command:
    ```binee -e kernel32.dll```

Issue 3: GetProcAddress() I don't know but I think when you guys started working on binee you had performance first in your priorities, the way you cached libraries/functions and just return the address was awesome, but it wasn't windows way. When I started working on forwarded exports I found it will be much better to actually implement GetProcAddress() to mimic windows, so in case the malware modified the tables in memory in a way to trick the emulator, binee will now handle this smoothly since it will do the behavior exactly like windows. I also added the feature of importing by ordinal since it wasn't previously handled and it should be noted that in windows if the function is a forwarded export, then its resolved recursively, I implemented this too.

To reproduce the issue:
    We wrote this small C program that modifies the entries in export table in memory then uses GetProcAddress(), previously this failed but now it works fine.

Issue 4: Added ordinal support for forwarded exports and imports. This is really straight forward I had this in mind since I first faced the issues in imports in binee, but I just postponed it.

Issue 5: Process Manager Most of malwares check open processes for anti-analysis techniques, others just use to check for processes, I wanted to have a single component to handle functions as (CreateProcess,TerminateProcess,Process32First), because handling each function on its own would have been a mess, I created the file processmanager.go, which can be seen as kernel storage for processes on the emulator. I then added the functionalities to add stub programs before starting emulation, extracted some processes from a windows used by a normal user to give an illusion of a normal machine and added them by default. I also wrote a simple C program to test it, its actually the same code I used to extract the processes.

Issue 6: NoLog Feature Added a bool variable in hook's structure that can be set in hook's declaration to allow not logging some hooked functions, as some function may cause noise since they are called a lot (memory functions) and they don't give much details about behavior.

Issue 7: LoadLibrary In forwarded exports, there was an issue, a library might not exist in the import table, but still be needed due to forwarding, so it has to be loaded. since loading a library in binee was done in steps and not a specific function that loads functions, I created a function that does the work for loading (retrieving from disk and adding ldr entries)

Issue 8: Threads (WaitForMultipleObject,WaitForSingleObject) I found out that binee does support multi-threading and scheduling but it doesn't really handle them well, it's just giving each thread its turn, which means functions like (WaitForSingleObject,WaitForMultipleObject), so I thought I should implement them since threads are core functionality in malware. The biggest problem was how to detect that a thread exited, I researched how windows handles thread, after reading lots of articles and reversing the actual windows flow, I found out that the call stack for the thread is something like (init thread - call function - exit thread), so I decided I should do the same. I re-implemented the CreateThread so that the function directly after thread function return would be RtlExitUserThread (ROP:return oriented programming) which is fully hooked and calls ThreadEnded in scheduler. The logic of handling threads happens there. To implement (WaitForMultipleObject,WaitForSingleObject), I made use of goroutines and channels, they are very efficient and lightweight by design. (I even researched a bit if we can actually parallelize binee to make it faster, but it came out the bottleneck of binee will be unicorn which can't be parallelized). So the logic I implemented was when a thread calls WaitForMultipleObject, its state is changed to waiting, it creates a goroutine which creates a channel for every object (thread) and pass them to every each one, when a thread is exited, in ThreadEnded function it sends a signal to the channel to say that you no longer have to wait for this object. after the condition is met (timeout or number of wanted objects finished), the state of the thread is changed back to ready and its run normally again.

To reproduce the issue:
the tests provided has a threading example, it now should work just like windows.

Issue 9: EFlags Upon context switching in binee, EFlags were not taken into consideration, this was very hard to notice since the behavior was very weird (jumps were taken that shouldn't be).

To reproduce the issue:
this is very hard to notice and you will have to go instruction by instruction, going with exact options I had this binary should reproduce it:
    SHA256(VirusShare_c70bea464ae1287f3b260ddc374f6c6a)= e3b870ab13a1db04c733b9c460a46fb57b8760de5fad9b613c91b902d5d2f054
    SHA1(VirusShare_c70bea464ae1287f3b260ddc374f6c6a)= 9c9111767ab702fbc7b768b2e77021b5d547fb63
    MD5(VirusShare_c70bea464ae1287f3b260ddc374f6c6a)= c70bea464ae1287f3b260ddc374f6c6a
but its really an obvious bug.

Issue 10: EnumResourceNames https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-enumresourcenamesa Its a function that enumerates resources by calling a passed function on the names of resources, in order to fully hook it, I needed a utility to call a std function, so I fully implemented it and created the utility. func CallStdFunction(emu *WinEmulator, functionAddress uint64, parameters []uint64) It takes an address and parameters, builds the stack in the std convention + the return point to return to the same IP, and then sets the current IP to the address that needs to be called. To test: SHA256(sample)= c9c89ce5eb015d0a364bd28de1d9b525a7d66ac4e527dfc10ade556f10c0829c SHA1(sample)= 52bf1744ef88fb2c1999985ab551e87ff0371a0f MD5(sample)= 0162349ac704cb1757edc73715a83a64

Issue 11: TLS wasn't allocated. To reproduce the issue: SHA256(sample)= 7bf87e4afdfc2a385a2a3d045fffed45ad0f56d7ca4ebe5dad03e18f376e9f4d SHA1(sample)= f11e5edb86148f31ccae18bc7d3029f500298e7c MD5(sample)= 0695c74d1f11b201eab7dd5b31808bc2 instructions: [1] 0x00404d00: mov edx, [+0x2c] [1] 0x00404d07: mov eax, [edx+4*eax] It will break and error since it will try referencing an unallocated memory. Issue 12: Hooks I implemented lots of hooks, partial and full hooks. I always depend on windows documentation for apis and ReactOs to implement hooks to mimic windows as much as possible.

mmn3mm avatar May 17 '20 21:05 mmn3mm