Notes on Practical Malware Analysis

General

  • ServiceMain= function needed for services (you can check it in the PE header)
  • Trailing A or W is if they use ASCII or Wide. Trailing Ex just means is a different version. Starting Zw or Nt means NativeAPI

Ch 0 - Primer

Nothing interesting. Types of malware and nothing else

  • While watching the stack, local vars will be below ebp (subtractions) while parameters/arguments above (additions)

Ch 1 - Basic Static Analysis

  1. Use hashes
  2. Multi vendor AV scan
  3. Search Strings (Unicode/wide vs ASCII)
  4. Identify Packers (PEiD)
  5. Dependency Walker (Use dependencies). For import export, also interesting for cardinal imports. Learn interesting API
  6. PE sections, in particular sizes (VirtualSize vs SizeOfRawData)
  7. ResourceHacker

Ch 2 - Virtual Machines

Nothing of interest on the setup except a discourse on LAN and internet. The rest is basic functionalities of VMs (like snapshots)

Ch 3 - Basic Dynamic Analysis

  1. Use a malware sandbox and get the results
  2. Run local VM (for dlls use rundll32.exe)

rundll32.exe DLLNAME, EXPORT ARGUMENTS (EXPORT is the exported function, can be ordinal)

  1. Monitors (procmon/filemon/regmon): it doesn’t capture everything. Filter because is cluttered
  2. ProcessExplorer (use the verify button and strings tab against the “process replacement tech”). Use this also to check if documents launch processes
  3. Dependency Walker (again)
  4. Regshot: snapshot of registry
  5. ApateDNS: first setup well the VM. Checks DNS requests
  6. NetCat
  7. WireShark
  8. INetSim: simulate common services

Ch 4 - x86 Assembly

  • rep: use EDI, ESI and ECX. ECX decremented until it’s 0. Operations (like mov or cmp) are between ESI and EDI that are incremented by 1 at each step (that 1 is of type relative to the rep opcode) [pag around 83 good reference]
  • some useful reference for unknown opcodes at http://www.intel.com/products/processor/manuals/index.htm

Ch 5 - IDA Pro

  • Show xref: press loc or sub and press x, same with data
  • var, arg and ebp-based frame: ida recognizes functions and parameters. If autoidentifaction fails, press P (or Alt+p -> BP based frame -> 4 bytes for saved registers) and create the function
  • “:” for comments
  • if something is interpreted as data instead of location and vice versa, press O. If code and data are mixed, press U or C
  • Use the standard symbolic constants (might need to load manually)

Ch 6 - Recognizing C Code Constructs

How to recognize high level things in low level

  1. Local vs Global vars: locals are referenced through stack while globals through memory addr
  2. Jumps that go down are usually if/else, jump that go up are usually loops
  3. For loop can be recognized by locating the four components: init, comp, exec,inc/dec
  4. Calling conventions: can be different but for WinAPI are standard 4.1. cdecl: push on the stack right to left. Caller cleans (usually with add), return in EAX 4.2. stdcall: as cdecl but callee cleans stack (THIS IS THE WINAPI ONE) 4.3. fastcall: first 2 params in edx and ecx, then in stack. Caller cleans, return on eax
  5. Init for calls is usually “push ebp, mov ebp,esp” and ends with “pop ebp”
  6. Switch, 2 types: 6.1. if style: cmp and jmp one following the other. jmp to the correct case and then uncon jmp out of everything 6.2. jmp style: uses an array to jump to the correct location. basically have in a var the offset of the array where the locations are
  7. Arrays: with things like [ebp+ecx4+7] you probably have an array (position, offsettype). The “7” in this case is the position related to ebp. Global arrays are just addr[offset*type]
  8. Structs: similar to arrays (position=ebp+something). Usually first load the struct obj, then i offset the value I want to access (with a flat value like +14h). Also use the functioins to understand the type (ex float instructions for float types). Use T to add structs
  9. To recognize a linked list, you must first recognize that some object contains a pointer that points to another object of the same type. The recursive nature of the objects is what makes it linked, and this is what you need to recognize from the disassembly.

Ch 7 - Analyzing Malicious Programs (Windows)

  • DWORD=32, WORD=16
  • Hungarian Notation:
  1. var starts with “dw”= DWORD; “w”=WORD; “H”=handle; obj(pointer wrappers really) that only WinAPI should touch; “LP”=LongPointer(32bit)
  2. ends with “Callback”=func called by WinAPI
  • File system functions:
  1. CreateFile(also for open, decided by dwCreationDisposition. Note that files can be anything, like sockets and IO devices)
  2. Read(Write)File. The value you give is the offset since the last read byte
  3. CreateFileMapping and MapViewOfFiles: load from disk to memory. Used to fuck up the Windows Loader
  • Stealth files: files but stealthier
  1. Shared files: “\serverName\share” or “\?\serverName\share”
  2. Namespaces Files: starts with “" (NT nmspc), “\. " (devices, notable “\. \Device\PhysicalMemory”)
  3. ADS (alternate data stream): add to another file in a stealthy way. It’s visible only when accessing the stream. Naming convention is normalFile.txt:Stream:$DATA
  • Registry. Five root keys (also called HKEY or hive). A key is a folder in the reg. A value entry is a pair (name, value)
  1. Roots: HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, HKEY_CLASSES_ROOT(types), HKEY_CURRENT_CONFIG(hw config), HKEY_USERS. First 2 are the most used
  2. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run for persistency (Autorun tool to check)
  3. Registry functions: RegOpenKeyEx, RegSetValueEx, RegGetValue
  4. file with .reg are human readable registry data. Opening it modifys the registry
  • Networks. same sockets as unix(bind, listen, accept etc.. all the same). PROTIP: WSAStartup has to always be called (good bp). WSAGetLastError for managing errors
  1. WinsockAPI is the basic one, WinINetAPI is the higher level one (Wininet.dll). Application layer protocols (InternetOpen, InternetOpenUrl, InternetReadFile)
  • Transfer Execution
  1. Hide in DLL. DLLs use DllMain function (management function called by the loader)
  2. New process: “CreateProcess”. STARTUPINFO struct used to give I/O to the new process. Save the embedded executbale on disk and execute it
  3. Threads: “CreateThread”. Can combo well with Dll loading. Also Fibers 3.1.. Mutexes: often use hard-coded names. “CreateMutex”, “OpenMutex”, “WaitForSingleObject” and “ReleaseMutex”. Used for checking that only one instance is running
  4. Services: basically code that is run in background by Windows itself. “OpenSCManager”(has to be called), “CreateService”, “StartService”. There are different service types (more infor at HKLM\SYSTEM\CurrentControlSet\Services). Use program “sc” to query services 4.1. WIN32_SHARE_PROCESS, store code in dll and combines different services in a single proces. my man svchost.exe is like that) 4.2. WIN32_OWN_PROCESS, store code in exe and runs as independent process 4.3. KERNEL_DRIVER
  5. COM: call other process code. Implemented as a client(code users)/server(code giver) framework. Must call “OleInitialize” or “CoInitializeEx” 5.1. COM objects are accessed via GUID called CLSID and IID, usually use “CoCreateInstance” 5.2. “Navigate” (part of IWebBrowser2 interface) launches Internet Explorer 5.3. Useful registry: The HKLM\SOFTWARE\Classes\CLSID\ and HKCU\SOFTWARE\Classes\CLSID 5.4. In order to identify what a malicious program is doing when it calls a COM function, malware analysts must determine which offset a function is stored at (INSERT key -> Add Standard Structure -> InterfaceNameVtbl) 5.5. For functions not available in IDA Pro, one strategy for identifying the function called by a COM client is to check the header files for the interface specified in the call to CoCreateInstance. 5.6. When COM object is loaded as a DLL, CLSID reg entry will be InprocServer32 rather then LocalServer32 5.7. COM server version use BHOs (run inside Internet Explorer). Usually exports DllCanUnloadNow, DllGetClassObject, DllInstall , DllRegisterServer , and DllUnregisterServer
  6. Exceptions(SEH): called by OS, HW or “RaiseException”. SEH information is stored on the stack (fs:0). Exception handlers are nested.
  • Kernel mode: SYSENTER, SYSCALL, or INT 0x2E
  • NativeAPI: NtQuerySystemInformation, NtQueryInformationProcess, NtQueryInformationThread, NtQueryInformationFile, NtQueryInformationKey, NtContinue(mixing up the redirection). PE header contains info is a program is exclusively NativeAPI

Ch 8 - Debugging

  • use the replay function of vmware if you step over a never returning function
  • breakpoint sw: INT 3 or 0xCC
  • breakpoint hw: can be checked by the program, but there are ways to check if they are checked (ex General Detect of DR7)
  • trap flag is used for single stepping
  • Exceptions: the way debuggers work (bps create exceptions). They are passed to the debugger by default.
  1. Exception Chance: First chance= when it happens, Second chance= if the program doesn’t handle it fully

Ch 9 - OllyDbg

  • Exethat use ASLR security will often be relocated not at imagebase 0x00400000. .reloc section contains a list of hardcoded addr to be relocated
  • Shift-F2 conditional bp. They are really cool
  • With olly you can load DLLs directly with a dummy loaddll.exe. It will exectue DllMain and then you can call single exports
  • Tracing (Run Trace): basically olly records what is happening. Can select an area to trace or “trace into”/“trace over”
  • 3 ways to manage exceptions: Step in, Step over, Run
  • Secret Shellcode Analysis Method: pag 196
  • Scripting is cool, check it at pag 201

Ch 10 - Kernel Debugging with WinDbg

  • The situation is: drives run in kernel and can be made by malicious actors. To interact with drivers, you have to use driver objects that send requests to “devices” that are made by the driver. Sometimes malware is exclusively kernel and do not even create devices
  • Driver work similar to Dlls. They have to be loaded in the kernel. DriverEntry is the equivalent of DLLMain
  • Drivers do not export functions but register callbacks
  • DeviceIoControl is a generic call to a device
  • The rest of the chapter is about setting up the environment and debug specific problems of kernel malware

Ch 11 - Malware Behavior

  • Types of malware
  1. Downloaders: download other malware, usually with URLDownloadtoFileA -> WinExec
  2. Launchers/Loaders: malware that execs other malware (usually contained in it)
  3. Backdoors: provide remote access and other functionalities. Reverse Shell: shell exposed by infected machines. Can be setup with netcat. Reverse shell can be basic o multithreaded (for encoded communications)
  4. RATs: remote manage a computer
  5. Botnet: network of zombie that do a single task
  6. Stealers: steal
  • GINA\WinLogon interception in msgina.dll [export Wlx functions], mitm attack on the dll can be done
  • Hash Dumping (pwdump and psh toolking)
  • Keylogging
  1. Persistence: registry (various ways Winlogon[hook messages], svchost[services], appinit_dlls[common dlls]). Trojanized system binaries(modify biraries to load malware). Load order Hijacking (uses the order in which winodws search for dlls and modifies it with KnownDLLs)
  2. Privilege Escalation (Metasploit) is rare: “SeDebugPrivilege”, “AdjustTokenPrivileges”, “OpenProcessToken”, “LookupPrivilegeValueA”
  3. User mode rootkit: first determine how the hook is placed, and then figure out what the hook is doing
  • IAT Hooking (override IAT)
  • Inline Hooking (override API itself)

Ch 12 - Covert Malware Launching

  • Usually malware has to be launched in privilege mode, so privilege escalation or the user has to give it
  1. Hide code in resources: FindResource, LoadResource, SizeofResource
  2. Process injection: use VirtualAllocEx and WriteProcessMemory 2.1. DLL injection: LoadLibrary, force DLL loading from a process. First get the handle (CreateToolhelp32Snapshot, Process32First, and Process32Next). Then open with OpenProces and CreateRemoteThread 2.2. Direct injection: same as dll injection but you inject directly in the process 2.3. Process replacement: start a process in suspended state, then use ZwUnmapViewOfSection and the usual VirtualAllocEx to replace the code of a process with the code of the suspended process
  3. Hook injection(SetWindowsHookEx, CallNextHookEx): hooks are used to intercept messages. Can be local(for the same process) or remote(for other process). Remote can be high level(exported by dll and executed after OS) or low level(executed before everything). Malware has to decide which thread to target
  4. Detour: library that enables the simple modification of binaries. Easy to add dlls (in a section called .detour)
  5. APC Injection: instead of generating a whole remote thread, you just call a procedure in the remote process. The thread has to be in an “alertable state” (WaitForSingleObjectEx, WaitForMultipleObjectsEx, Sleep) 5.1. User mode APC: (QueueUserAPC) 5.2. Kernel mode APC: (KeInitializeApc, KeInsertQueueApc)

Ch 13 - Data Encoding

All forms of data modification done to hide content. Commonly used to cover network comms, hide configs, strings

  • Basic ciphers: caesar, XOR, NULL-preserving single-byte XOR (doesn’t encode NULL and key bytes), other basic opcodes (add-sub, rol-ror, rot), multibyte encoding, chained(CBC)
  • Identifying XOR loops: search all for and remove the ones that are on the same register. If it is a small loop it is a good candidate
  • Base64: padding can be removed and still work. There is a string used for enc/dec (ABCD…), careful, this string can be customized
  • Common CryptoAlgos: guess the technique and the key
  1. Recognize strings and imports: OpenSSL library, functions that start with Crypt, CP or Cert. Use sw made for it like FindCrypt2 or KANAL. These work by searching for a magic constant (RC4 does not have it)
  2. High Entropy Content: 64byte -> 6. 256byte -> 8. Learn to read the graph
  3. Custom Encodings: Finding the encoding algorithm the hard way entails tracing the thread of execution from the suspicious input or output. Basically, trace
  4. Decoding: let the malware do it (even by directing it, use scripting pag 292) or code (pycrypto) it urself (or cyberchef)

Ch 14 - Network Signatures

Countermeasures for network threats

  • IDS: Detection, IPS: Prevention
  • Before running malware check logs, alerts and so on from where it was discovered -OPSEC: don’t get fucked by malware when analyzing
  1. Don’t use internet, if you have to, use tor-proxy-webanonymizer-vpn-amazonec2
  2. Search engines are safe but might generate crawler activity
  • IP Info: get Regional Internet Registries(RIR). Use third party services for anonymity (DomainTools, RobTex, BFK DNS logger)
  • Snort IDS[learn the keywords]: rules based on characteristics in the payload used to filter packets (pattern matching)
  • Emerging Threats: list of signatures (YARA?)
  • Level of analysis: surface(sandbox), communication complete(every type of comms is understood), operational replication(complete simulated malware through our server), code coverage
  • Camouflage techs:
  1. Mimic existing protocols and put things in filed like they are not supposed to
  2. Use the server for legitimate use to cover illegal activity
  • identify ephemeral data and hardcoded data
  • Custom parsing routines are generally organized as a cascading pattern of tests for the initial characters

Ch 15 - Anti-Disassembly

  1. Wrong offset disassembly(rogue-byte): crazy jumps that jump just a byte and similar. Check out different disassembly techs (usually calls and pointers create problems): 1.1. Linear: use instruction length and go on. Problem is that sometimes you find data and not code so it fucks up (ex. jmp tables) 1.2. Flow-oriented: writes down locations to disassemble (i can mix trick?). I can put call+string and hide things (pag 333). With ida i can clean code by manually selecting it ad data (D) or code (C). Next techs exploit the fact that disassemblers have to choose which branch analyze first and that might create conflict
    • Double jump: jz+jnz is an unconditional jmp but it creates problem to the disassembler if you jump inside an instruction
    • Jmp with constant: condition is fixed so the jump too
  2. Wrong offset but impossible to fix: use a byte for 2 instructions (basically jumps to itself). EB FF C0 48 results in a jmp in itself plus inc eax dec eax. You can use it as nop. The solution usually is to make the nop apparent, the problem is that it might interfere with graphing
  • noping script at 340
  1. Function pointers: function pointers are not always understood by disassaemblers and might confuse xref (can still be fixed manually, with AddCodeXref)
  2. Magic jmp (push+ret). You already know
  3. SEH hack: add a SEH handler and raise exception. It results in function that doesn’t seem to be called but that are
  4. Stack Frame Terrorist: disassemblers can guess the parameters passed to a function. You can do some damage (62 parameters functions). It exploits the previously cited branches that produce different disassembly and the default is the wrong one

Ch 16 - Anti-Debugging

  1. API check: IsDebuggerPresent, CheckRemoteDebuggerPresent, NtQueryInformationProcess, OutputDebugString
  2. Struct check: Check PEB(fs:30h) > BeingDebugged[2 methods, mov and push/pop], > Reserved4 > ProcessHeap > Flags, > NTGlobalFLag
  3. System residue: Registry Keys, FindWindow/check filesystem or ram
  4. Behavior: INT scanning: check for 0xCC in the code, Checksums, timing: rdtsc, QueryPerformanceCounter, GetTickCount
  5. Debugger functionalities: TLS Callbacks(easy check with ida), SEH, Interrupts (to annoy, 0xF1 is really cool)
  6. Vulnerabilities: Debugger parse the PE Header differently than the loader, string passed to OutputDebugString

Ch 17 - Anti-VM

These are specific anti VMWare tactics

  1. Artifacts: specific processes, services, registry, hardware
  2. Hardware VM interactions (kernel calls that do not make the VM intervene: sidt, sgdt, sldt, smsw, str, in ,cpuid): RedPill, No Pill(disable accelleration), querying I/O(0xa 0x14), str technique(only single process hw)
  • pag 379 config for less detection

Ch 18 - Packers and Unpacking

  • Packer stub tasks: Unpack, fix imports, get the OEP
  • Import hiding techs: no hiding, partial hiding(just one func per dll), simple total hiding(import only LoadLibrary and GetProcAddress), comples total hiding (stub is complex, done in shellcode)
  • Tail Jump: jump to OEP (jmp, ret, call, NtContinue, ZwContinue)
  • How to check if is packed: two magic imports, olly and IDA recognize it, section names, abnormal section sizes (SizeOfRawData or VirtualSize), DetectItEasy, Entropy Unpacking Techs: Automatic with PE Explorer(NSPack, UPack, UPX), Manual
  • FINDING THE OEP:
  1. Automatic tools (FindOEP Section Hop)
  2. Manual: last jmp before useless instructions, very far away, IDA will mark it in red, write down the first push of the stub and when it pops is the jmp, break after every loop, break at GetProcAddress (let’s you jump some code), break in a function called by the program and go backwords (check for windows wrapper that calls GetVersion and GetCommandLineA or GetModuleHandleA) (functions start with push ebp; mov ebp, esp)
  • REPAIR THE IAT: nothing new
  • TRICKS FOR COMMON PACKERS:
  1. UPX: easy and automatic, but care because it might be a fake and modified UPX
  2. PECompact: uses exceptions(chapter 16). OEP is a jmp eax followed by 0x00
  3. ASPack: self modifying code, automatic. OEP is based on a PUSHAD, find the POPAD
  4. Petite: one import per library, OEP find through stack
  5. WinUnpack: automatic, push ret tail jump, hard
  6. Themida
  • jumps over 0x4000 are to check
  • stubs have many conditional jumps and returns in the middle of a function, but the code around the OEP should not have these unusual elements.
  • you can static analyze even when not able to dump perfectly everything
  • If you have to unpack dlls, transform them in EXE first, unpack them and retransform them in DLLS

Ch 19 - Shellcode Analysis ?

Shellcode: payload of raw executable code. PIC: position independent code (no hard coded addresses) Identify exec location: call/pop, fnstenv

Ch 20 - C++ Analysis ?

Ch 21 - 64-Bit Malware ?