-
Notifications
You must be signed in to change notification settings - Fork 73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bugs found while testing on malware unusual packers + Hooks implemented #70
Open
mmn3mm
wants to merge
110
commits into
carbonblack:master
Choose a base branch
from
Mal-RD-team:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Tested new feature : Handling resources and adding support to functions [LoadStringA , LoadStringW , FindResource,LoadResource,SizeOfResource,LockResource].
(feature) add flag to print resources
Processmanager
…annels to threads
Windowsthreads (WaitForMultipleObject,WaitForSingleObject)
…esolving to handle forwarded exports
… forwarded exports
Forwarded exports
…into RemoteThreadManager
- If a user supplied the path to DLLs in `-r` option without a trailing backslash, it didnt work due to path concatenation instead of using the built-in `Path.join()` function. - Examples of the previous issue: - `binee.exe -r "C:\Windows\system32\"` used to work - `binee.exe -r "C:\Windows\system32"` didnt work - Now both work fine. - Also changed the variable name `path` to `pePath` in many locations to avoid conflict with the package `path`.
- Hardcoded paths included `%windir%\system32` only. It should include `%windir%\SysWoW64` too. - If a user supplied a custom path using `-r` switch, we should search that path too; not just its `windows\system32` subdirs. - Now all the tests (excluding x64 ones ofc) work perfectly using SysWow64 DLLs
…eep minute in hooks
- Now Binee auto detects the correct paths for system DLLs depending on: - The host machine's arch - The target PE file's arch (gitignore) Untrack the damn workspace.xml
Fix path issues preventing SysWOW64 DLLs from working
…randomization of heap allocation. (this is not an original windows behaviour but it has to be done here)
# Conflicts: # windows/hooks.go
Handling remote threads created by the emulated process
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
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.
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.
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.
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).
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.