- Use WinDbg for kernel debugging
- Apply hardware data breakpoint for analyzing data flow
- Understand TDI Network Service
- Understand key I/O data structures such as _IRP and _IO_STACK_LOCATION
- Understand deferred procedure call
- Understand the use of system timer for delayed actions
- Understand the use of WorkItem queue and worker routines
- Operating Systems
- Assembly Language
- Operating System Security
We now finish the last part of raspppoe.sys and look at its malicious actions regarding the use of deferred procedure call (DPC) and establishment of a TCP connection to remote server. We show how to use WinDbg to find out an encrypted configuration file that contains the list of malicious servers (IP and domain names) that Max++ tries to contact. In this tutorial, combined with Tutorial 24, we also show the multi-thread tricks played by Max++ to make the analysis harder. The network activity (setting up TCP connection and sending and processing data) is accomplished via multiple threads. This creates trouble in debugging.
Our analysis starts from _+38A1.
2. Lab Configuration
We will use the instructions of Section 2 of Tutorial 20. In the following we just remind you of several important steps in the configuration:
(1) You need a separate image named "Win_Notes" to record and comment the code. You don't really need to run the malware on this instance, but just to record all your observations using the .udd file. To do this, you have to modify the control flow of IMM so that it does not crash on .sys files. See Section 2 of Tutorial 20 for details. Jump to 0x100038A1 to start the analysis.
(2) The second "Win_DEBUG" image has to be run in the DEBUG mode and there should be a WinDbg hooked from the host system using COM part -- so here, we are doing kernel debugging.
(3) Set a breakpoint "bu _+38A1" in WinDbg to intercept the driver entry function.
3. Code Starting at _+38A1
Figure 1. Last Part of rasppoe.sys |
As shown in Figure 1 (first highlighted part), the first call is IoAllocateWorkItem(PDevice_Object). It produces a structure named IO_WorkItem that describes a work item for system threads. Using WinDbg, we can easily identify the device_object passed to the call.
kd> dt _DEVICE_OBJECT ffa50bb8 -r1
nt!_DEVICE_OBJECT
...
+0x010 DriverSize : 0x8e00
+0x014 DriverSection : 0x8131d310 Void
+0x018 DriverExtension : 0x81131888 _DRIVER_EXTENSION
+0x01c DriverName : _UNICODE_STRING "\Driver\Disk"
Then the created IoWorkItem is saved to a global variable.
Challenge 1. Find out when the IoWorkItem is used using data breakpoints.
The next step performed is a call to KeInitializeTimer and the timer object is also saved in a global variable.
Challenge 2. Find when and how the timer is used.
As shown in Figure 1, the subsequent action is a call to KeInitializeDPC. This is an important call. According to MSDN document [1], the prototype of KeInitializeDPC is shown below. Here DPC means deferred procedure call. It is frequently used to service I/O requests (so that low priority calls will be executed later). The function creates and stores a _DPC structure in its first parameter, and registers a function as a second parameter.
VOID KeInitializeDpc( __out PRKDPC Dpc, __in PKDEFERRED_ROUTINE DeferredRoutine, __in_opt PVOID DeferredContext );
Using WinDbg, we can soon infer that the deferred procedure to call later is located at _+3016.
kd> p
_+0x38c2:
faf4f8c2 6a00 push 0
kd> p
_+0x38c4:
faf4f8c4 6816f0f4fa push offset _+0x3016 (faf4f016)
kd> p
_+0x38c9:
faf4f8c9 be7821f5fa mov esi,offset _+0x6178 (faf52178)
kd> p
_+0x38ce:
faf4f8ce 56 push esi
kd> p
_+0x38cf:
faf4f8cf ff152001f5fa call dword ptr [_+0x4120 (faf50120)]
We can set a breakpoint at _+3016 (bp _+3016) and see what is going on.Next, Max++ calls another interesting function KeSetTimerEx to link all the previous actions together. According to [2], the prototype of KeSetTimerEx is listed in the following:
BOOLEAN KeSetTimerEx(
__inout PKTIMER Timer,
__in LARGE_INTEGER DueTime,
__in LONG Period,
__in_opt PKDPC Dpc
);
The KeSetTimerEx uses a previously constructed timer to set an "alarm" so that after some
timethe DPC procedure that _+3016 is triggered.
Challenge 3. Prove that the alarm will trigger _+3016 15 seconds later.
4. IO Worker Routine that Connects to Server
Figure 2 shows the function body of _+3016. It's mainly a call to IoQueueWorkItem.
Figure 2. Function body of _+3016 |
VOID IoQueueWorkItem(
__in PIO_WORKITEM IoWorkItem,
__in PIO_WORKITEM_ROUTINE WorkerRoutine,
__in WORK_QUEUE_TYPE QueueType,
__in_opt PVOID Context
);
Using WinDBG to dump the stack contents, we can easily infer that the WorkerRoutine is located at _+1a0c (in our fiture: it's named DPCWorkItemFunc_connects_to_server). We now proceed to the analysis of _1a0c. By MSDN [4], WorkerRoutine should have the following prototype:
VOID WorkItem(
__in PDEVICE_OBJECT DeviceObject,
__in_opt PVOID Context
)
We now proceed to analyze the worker routine _+1a0c. At the first instruction of _+1a0c, we dump the stack contents as following:
kd> dd esp
fafb3d64 80564610 8114edf0 00000000 805622fc
fafb3d74 fafb3dac 804e426b 81227cb0 00000000
fafb3d84 812e9da8 00000000 00000000 00000000
fafb3d94 00000001 80562334 00000000 812e9da8
fafb3da4 00000000 805645fd fafb3ddc 8057aeff
fafb3db4 81227cb0 00000000 00000000 00000000
fafb3dc4 fafb3db8 00000000 ffffffff 804e2490
fafb3dd4 804f8ab0 00000000 00000000 804f88ea
kd> dt _DEVICE_OBJECT 8114edf0 -r1
nt!_DEVICE_OBJECT
...
+0x01c DriverName : _UNICODE_STRING "\Driver\Disk"
...
Clearly, here 80564610 is the return address, 8114edf0 is a device object (see the prototype of WorkItem routine above), and 0x0000 is the context. You can verify that 8114edf0 is a disk device. Figure 3 shows the simple function body of _+1a0c. It consists of only 4 instructions. At 10001A0E, it pushes the offset of an object attributes into the stack and then it calls a function (readConfig_ConnectToServer) located at _+18d6.
Figure 3. Worker Item Routine |
kd> dt _OBJECT_ATTRIBUTES faf4a050
nt!_OBJECT_ATTRIBUTES
+0x000 Length : 0x18
+0x004 RootDirectory : (null)
+0x008 ObjectName : 0xfaf482e8 _UNICODE_STRING "\??\C2CAD972#4079#4fd3#A68D#AD34CC121074\{49B474EB-92D0-464f-B1DD-1F37AABF9D95}"
+0x00c Attributes : 0x40
+0x010 SecurityDescriptor : (null)
+0x014 SecurityQualityOfService : (null)
5. Read Configuration File in Hidden Drive and Connect to Remote Server
Figure 5. First Part of _+18d6 |
kd> db fafb3b3c
fafb3b3c 3c 69 70 3e 38 35 2e 31-37 2e 32 33 39 2e 32 31 <ip>85.17.239.21
fafb3b4c 32 3c 2f 69 70 3e 3c 68-6f 73 74 3e 69 6e 74 65 2</ip><host>inte
fafb3b5c 6e 73 65 64 69 76 65 2e-63 6f 6d 3c 2f 68 6f 73 nsedive.com</hos
fafb3b6c 74 3e 4e 80 98 3b fb fa-12 cc 51 80 08 00 00 00 t>N..;....Q.....
fafb3b7c 00 00 00 00 98 3b fb fa-2e cc 51 80 01 20 f1 df .....;....Q.. ..
fafb3b8c 02 02 00 00 5d 34 4e 80-4a 61 00 00 f6 32 4e 80 ....]4N.Ja...2N.
fafb3b9c fd 32 4e 80 12 c6 05 fb-30 00 00 00 38 3c fb fa .2N.....0...8<..
fafb3bac 08 56 6f 80 00 0d db ba-08 40 00 00 00 00 00 00 .Vo......@......
Challenge 1: replicate the success to find out the contents of the configuration file of Max++.
Figure 6 shows the rest of function _+18d6. The logic is very clear. At 0x10001983, it calls a self-defined function getTagContent (located at _+1486) to look for a tag <ip> in the configuration file. It soon finds out the ip string 85.17.239.212. Then it calls system function RtlIpv4StringToAddressExA to generate the 32-bit representation of the IP address.
Challenge 2. Analyze function _+1486 (getTagContent). What are its parameters and output?
Figure 6. Rest of Function _+18d6 |
kd> dd esp
fafb3a28 d4ef1155 00005000 00000001 ffb4b850
fafb3a38 812e9da8 652e7ecd a4362152 3c135905
fafb3a48 ee8d12d7 d1b04962 0150df55 0fd8ad5f
It is not hard to see that d4ef1155 is the integer representation of IP address 85.17.239.212 (note the byte sequence and the HEX translation, e.g., 0x55 is decimal number 85).
6. Establish the TCP Connection
Function _+1832 establishes a TCP connection to the 85.17.239.212/5000, however, it does not send anything. The TDI_SEND operation is actually issued by the system thread discussed in Tutorial 24. Why doesn't Max++ try to accomplish in one thread? It's creating trouble for analysts.
Figure 7 presents the function body of _+1832 here. We omit most of the analysis and leave the details to you.
Figure 7. Establish the TCP Connection |
As shown in Figure 7, Max++ follows the general procedure of establishing a TCP connection -- it first binds the address and then requests the connection.
Challenge 4. Completely analyze all the details of function _+1832
References
1. MSDN, "KeInitializeDPC routine", available at http://msdn.microsoft.com/en-us/library/windows/hardware/ff552130(v=vs.85).aspx.
2. MSDN, "KeSetTimerEx routine", available at http://msdn.microsoft.com/en-us/library/windows/hardware/ff553292(v=vs.85).aspx
3. MSDN, "IoQueueWorkItem", available at http://msdn.microsoft.com/en-us/library/windows/hardware/ff549466%28v=vs.85%29.aspx
4. MSDN, "Work Item Routine", available at http://msdn.microsoft.com/en-us/library/windows/hardware/ff566380%28v=vs.85%29.aspx
BlueHost is ultimately one of the best hosting provider for any hosting services you might require.
ReplyDelete