Revealing Stealth Malware UMD CMSC389M Xeno Kovah – Jan. 2013 xkovah at gmail Subject line starting with "UMD:" 1 All materials is licensed under a Creative Commons “Share Alike” license. • http://creativecommons.org/licenses/by-sa/3.0/ 2 Outline • ProcMon, WinDbg userspace vs. kernel, Existing stuff review • Lab: Using WinDbg, live system analysis with GMER, Tuluka, VBA, and XueTr 3 Runtime Importing • Other functions that are important to malware are LoadLibrary() and GetProcAddress(). • LoadLibrary() can be called to dynamically, on demand, load a DLL into the memory space of the process • GetProcAddress() gives the address of a function specified by name, or by ordinal (which we may talk about briefly). This address can then be used as a function pointer. • These functions are often abused to make it so that which functions the malware actually uses cannot be determined simply by looking at the INT. Rather, the malware will have the names of the imported libraries and functions obfuscated somewhere in the data, and then will deobfuscate them and dynamically resolve them before calling the imported functions. 4 Runtime Importing 2 • When an attacker is using the more sophisticated methods of DLL injection, he is not necessarily injecting a full, well-formed PE file DLL into another memory. He may just be injecting small snippets of asm. • When that's the case, he will typically inject code which walks the PE headers to find the exports table of kernel32.dll to find GetProcAddress() and LoadLibrary(). 5 Runtime Importing 3 • In *your* case, since you're loading a full, wellformed DLL, you can just put calls to these functions into your DLL, and the OS loader will happily fill in your IAT so that you can call these easily. • Therefore for this homework, you can use these two functions, without having to walk headers, like is in the previous slide deck, but which I didn't cover in class (so I'm not deleting it from the deck, but it isn't required for the homework or final) 6 Process Monitoring with ProcMon • ProcMon is another Sysinternals tool (like Process Explorer, and Autoruns.) 7 When you start it up the first time, it should ask you what you want the filter criteria to be. This is basically a question of what you want to monitor. To make this less noisy, you should only monitor a specific process to start with. Change the monitoring criteria to "Process Name" and then enter a process name then click Add 8 You should consequently see a new green checkbox appear in the rules. Hit Apply and then OK 9 To make sure that this doesn't eat a ton of RAM storing information about events that you're filtering out, the first thing you want to do is change it so that it Drop[s] Filtered Events 10 The top bar lets you toggle what type of events you want to see, as well as clear existing events and edit the filter. Event Toggles Filter Clear Events Registry File Network Process 11 The Operation column can give you hints on what functions are being called, though it's by no means a 1:1 mapping (but it's closer in the registry case than in the file case) 12 This gives a partial explanation which will make more sense next week 13 WinDbgging Userspace • As I've shown you can use WinDbg to debug userspace programs as well as kernel ones. • Some commands in the WinDbg cheat sheet are kernel-only though. If something doesn't work, double check it against the in-windbg help (which is actually very helpful) 14 Run WinDbg (as Administrator if on Win 7). Once it's running, open an executable Find the exe you want to debug You can give it command line arguments at the bottom if you want. Or you can tell it to execute from a given directory (incase you want to give a relative path to an input file for instance) 15 Once it starts, you'll get a single command window like normal. At this point you should set up your WinDbg windows however you want them, or preferably like is specified in the first day part 2 slides. Don't forget to go to File->Symbol Path and enter the symbol path given in the slides. Your VM will need internet connectivity in order to download symbols from microsoft. And always, just for good measure, use ".reload" to make sure your symbols are reloaded. 16 Once you have it set up, what then? Well then you can start setting breakpoints on the functions you think are responsible for the activity you're interested in. The breakpoint will allow you to examine the values of registers, memory, and the stack *exactly* the way they would look from your inline/IAT hook's perspective when it's first called. 17 A simple first command is "lm" this lists the modules that are currently loaded. In userspace, it will list .exe and .dll modules in a specific process' memory space. In kernel, it will list the .sys kernel drivers which are loaded in the kernel memory space. You can also use "lmf" to list with file names. See the help for other forms of "lm" If I just hit "g" to go (continue execution) at this point, the debugger tells me that a couple more modules loaded. Hmm, and one of them was my IAT hooking module. For debugging purposes it sure would be nice if I could stop right when that gets loaded, and then set a breakpoint on my DllMain() or something, so I can step through the code and make sure it's right… You could set a deferred breakpoint which should technically get set when it loads, but we really want to make sure it gets set… We can use the "sxe" command to set an exception (debugger stop) whenever a particular action occurs. The particular action we want here is module load. So by looking at the windbg help, we see that we want something like "sxe ld". But even better than that, is some magic Xeno's going to lay on you right now, which will tell you exactly which module just loaded. That command is: sxe -c ".lastevent" ld So let's restart the process and do that before we hit g and let the rest of the modules load… 19 From here you should set the Symbol File Path to the path where your DLL was built, because the .pdb (portable debug) file will be in that same directory, and windbg will need that file so it can find your DllMain when you try to set a breakpoint on it (like "bp StudentAppInitHookIAT!DllMain") Then you can experiment with stepping through your own code to make sure it's doing the right thing and/or setting breakpoints on the functions you think pertain to viewing registry keys Example: modifying cmd.exe's FindFirstFile/FindNextFile data structures specifically to change a file name • Reminder: if you look at the bottom of the documentation you will see that actually FindFirstFile is technically normally called FindFirstFileW or FindFirstFileA. You also see this if you just use tab completion in windbg • Reminder: if you look at the documentation you will see that these functions take two inputs, the first is used only for input, and the second is just passing the address of a structure, so that the function can fill in the structure data, and that will be the output • Reminder: see the 1-7-2013 slides to see the x64 calling convention and what parameters to a function are passed in what variables 21 So now you've set some speculative function breakpoints because you want to see what data is passed in/out You let the program continue, by hitting "g" to go. Then you go do a "dir" in cmd.exe and it breaks at one of your functions you theorized might be involved in file operations But before we dig too deep into it, let's keep continuing to see what else is called… So it looks like FindNextFile is getting called a bunch. And if we happen to take a peek back at the cmd.exe window, we even see that there's a partial directory listing at this point So by RTFM we know that the address of the data structure will be in RDX right when FindNextFileW is called. So look at the value in RDX in a registers window… And then stick it into a memory window Now what you want is some way to see the data in that data structure location once FindNextFileW is done. There are many ways you could do this. You could look at the assembly in the disassembly window, and use the debugger's "step in" capability (as all debuggers have) in order to step into the function and find where the function has a "ret" instruction, signaling that it's done, and set a breakpoint on the ret. You could just look at the memory pointed to by the stack pointer ESP to find the saved EIP that you know must have been pushed onto the stack as a side effect of the call when whatever parent function called FindNextFileW. But I'm going to let you do it the easy graphical way. Just open a new calls window (which shows a stack backtrace) Open a disassembly window if you didn't already. Then double click on the thing below FindNextFileW (this is its parent, and fwiw it's in cmd.exe itself). This will force the disassembly window to jump to the cmd!FindNext + 0x3C Now that this line immediately after the call to FindNextFileW is selected, you can just set a breakpoint on this line, so that you will be able to inspect that EDX value immediately after the function has returned. So click the break icon and then the line is going to turn pink or something :P Hit "g" to continue, and the next place you'll hit is that line Meanwhile, back in the memory window… Hmm, that kind of looks like it might be a wide character file name there on the end. "adplus.doc"? So maybe the way this FindNextFile function works is, it's called, it gets one file name at a time, it fills in this WIN32_FIND_DATA, and then cmd.exe take whatever comes back and prints it to the cmd window. So if that were true, I could just click in the memory window change that string like so… Hit "g" to continue, and then see what I shall see in the cmd output window Hmm…so I guess if I were an attacker executing code every time FindNextFileW was executed, I could keep checking that string field of the WIN32_FIND_DATA and if it's ever "adplus.doc" I could always change it to "adpluw.doc". OR. I could do other things Tool interpretation 27 Import Address Table (IAT) Hooks (GMER) This is the address in the IAT pointing somewhere other than where it should (based on the Exports Address Table (EAT) of the exporting module This is the module doing the importing Telling you that this is an IAT hook If GMER can, it tries to infer which module space the function pointer is pointing into. And if there's version information in that module, it pulls that out too This is the function being imported by the first module and exported by the second This is the module doing the exporting 28 Inline Hooks (GMER) PE section where the hook resides module within process memory hooked process name process ID (PID) function name within module number of bytes that changed specific virtual memory address where the change is found if control flow redirect (call, jmp) module space where it's redirected to if it is within a module address range interpretation of changed bytes (if possible) 29 !chkimg (WinDbg) • You can also find modifications to static code/data areas with the !chkimg windbg command. It checks the version in memory against the file on disk • E.g. to detect one of the above hooks seen with gmer, you could attach to taskmgr.exe, check your symbols, do your .reload and then do !chkimg -d kernel32 30 False Positives McAfee HBSS HIPS But when security software uses hooks like rootkits…you can remove its hooks just like you can remove a rootkit's hooks in order to blind/disable it. This is especially nice because it means you can defeat security software without resorting to reverse engineering, because they always get touchy about you reverse engineering their stuff (as if the attackers can't) 31 How to mount an ISO in VirtualBox Go into your storage settings. Select the CD drive. Then click on the CD icon here Select the below option and then navigate to the ISO that you want mounted inside your VM 32 How to install VirtualBox additions & then set up a shared folder Install the guest additions. It will then prompt you inside the VM to install some windows programs & drivers. Just accept all the defaults 33 Go to your settings and then click this 34 If this isn't a valid path on your host OS, the "OK" will be greyed out Name in host OS Name in guest OS Windows Linux 35