- Joined
- 11 yrs. 8 mth. 23 days
- Messages
- 5,010
- Reaction score
- 11,818
- Wallet
- 13,191$
- [email protected]
Deep Dive into a Custom Malware Packer
c0d3inj3cT July 17, 2013
Introduction
In this article we will look in depth at a Custom Packer used by a Malware that was recently found in the wild. This packer is interesting for several reasons. It uses several layers of packers including the well-known UPX Packer which is only used to mask the underlying custom packers.
It also uses a clever way of injecting code into a remote process and resuming its execution from there. I have included necessary screenshots with snippets of assembly language code sections along with comments, stack parameters for API calls and views of memory dump. This will help in following the article while the unpacking method is described.
An Overview
Since the unpacking method is described in depth and there are several layers, I am giving a high level overview of the algorithm at first before going in depth.
1.It uses a UPX packer which is used only for the purpose of masking the underlying custom packers. UPX packers as we know can be easily unpacked.
2.The first layer of a custom packer uses a lot of code which has been placed only to increase the size of code we have to go through while reversing. With the help of few example code snippets, this has been explained. It’s used to deter reverse engineering.
3.It stores the encrypted subroutine at a particular offset within itself. This subroutine is later decrypted and executed.
4.In the second stage, the decrypted subroutine performs another level of unpacking. There is an encrypted malicious executable embedded inside the main image which is decrypted in two phases.
5.After the decryption of the malicious executable, it proceeds to modify the header of the main image. It copies the various sections of the malicious executable like PE Header, .text, .rsrc, .reloc to the start of main image.
6.It then calls the AddressOfEntry point of the malicious executable. This code will spawn a new process, svchost.exe in a suspended state.
7,It then proceeds to inject the malicious code in svchost.exe process and resume its execution.
Unpack the UPX
This executable uses a clever way of packing. It uses a well-known packer called UPX which is detected by most automated sandboxes and packer identifiers like PEiD and ProtectorID.
So, we start by unpacking the UPX packer. As already known, UPX packers can be unpacked using the ESP + hardware breakpoint trick. So, let us unpack it using this method.
This is how the Original Entry Point of a UPX packed binary looks:
We step over the PUSHAD instruction which will save the contents of all the registers on the stack.
Once we step over PUSHAD, we will follow ESP in memory dump and set a Hardware Breakpoint at the WORD present at that memory location. The reason this is done is: once the unpacking completes, POPAD instruction will be executed that will restore the contents of registers.
As a result, this memory location will be accessed and modified. So, we set the hardware breakpoint as shown in the screenshot below:
Once we run the executable after setting the hardware breakpoint, we break at the following memory location:
Next, we set a breakpoint at 0x004170B4 to skip over the loop.
Once we step over this, we reach the Original Entry Point at 0×00402690.
In most cases, this is the unpacked executable and now you can start stepping through the code to understand the malware. So, let’s continue with that.
Identification of Unnecessary Code Sections
This is how our Original Entry Point at 0×00402690 looks like after unpacking UPX:
This looks good, so let’s continue.
After tracing the code further from OEP, we reach a CALL to the subroutine at address, 0×00401020.
In most cases, you would reach the code corresponding to malware after this. So, let’s see:
This subroutine contains a lot of code which has been placed to deter reverse engineering. For instance, if you check the section of code below:
It moves a constant DWORD into a memory location, [EBP-58] and then compares it with another constant DWORD, followed by a check for whether they are unequal. Since they will always be unequal, the Jump will be taken.
Similar lines of code were observed in multiple places in the subroutine which were added only to increase the size of code that we have to go through while reversing.
Similarly, another section of code:
It moves a constant DWORD into [EBP-54], and then moves it to EDX, multiplies with itself, and then adds it to the result and stores back in the memory address.
However, this value is not relevant to us for reversing.
Decryption of Custom Unpacking Subroutine
Proceeding in this way and skipping over sections of code that use code similar to above, we reach a CALL to VirtualAlloc with the stack parameters as shown below:
It allocates a new memory with a size of 0×1830 bytes.
It is important to note that, VirtualAlloc is a good way of locating the Original Entry Point of an executable. The reason being, while unpacking it’s common to see a CALL to VirtualAlloc which allocates a new memory region. Encrypted data is copied to this memory location and then decrypted.
If the data at this memory location is executed later on, then it means we have unpacked it or reached the original entry point (it’s possible that there is more code obfuscation later).
In our case, the call to VirtualAlloc() allocates a new memory region at base address, 0x00C50000
Tracing the code further we reach a CALL to subroutine at 0x004016F0 as shown below:
Tracing this subroutine further, we locate our first decryption routine:
The encrypted data is stored at memory address, 0×405028as shown below:
Here is a high level overview of the decryption subroutine:
1.It reads one DWORD at a time from the encrypted data.
2.It modifies the DWORD by passing it to a subroutine at 0x00401A80
3.The DWORD modified above is passed to a second subroutine at 0x004014E0
4.The final modified DWORD is written to the newly allocated memory region at 0x00C50000
5.There is a counter which is used to keep track of the number of DWORDs read from the Encrypted Data section. A total of 0x12A DWORDs are read, modified and written to the newly allocated memory region.
Below is the code explanation with comments:
Here is the first DWORD modification routine:
Here is an explanation of the code with comments:
The result of the first DWORD modification routine is passed to the second subroutine at: 0x004014E0
Here is the second DWORD modification routine:
Here is the code with comments:
After returning from the second subroutine, it will write this modified DWORD in the newly allocated memory region:
Here is an explanation of the code with comments:
Once the decryption has completed, we have the decrypted data present at 0x00C50000 as shown below:
Now, it calls the decrypted subroutine at 0x00C50000 as shown below:
Unpacking the Custom Packer – Stage 1
Once we step into this subroutine we are the first decrypted subroutine as shown below:
Here is an explanation of the code:
We will step into the first subroutine at 0x00C501FA which is used to get the address of different APIs:
Here is explanation of the code with comments:
It uses the subroutine at 0x00C502BF to get the base address of kernel32.dll by parsing the PEB structure. This is a common method used by shellcodes and various malwares to dynamically find the base address of kernel32.dll:
The next subroutine at address, 00C5030Eis used to get the address of GetProcAddress API which will later be used to get the address of different APIs.
It proceeds to find the address of different APIs using GetProcAddress as shown below:
All these function pointers are stored in memory, as shown below:
Now that it has retrieved the pointers to some APIs, it starts with another decryption routine.
The code of malicious executable is located at memory address, 0x004054D0
First, let’s take a look at this encrypted data:
If you look at this encrypted data, you will observe a pattern. After every DWORD, we have the WORDs 0×0050 or 0×0051 corresponding to ASCII values P. or Q. respectively.
Now, let’s check the decryption routine. It is mentioned below with comments:
This subroutine is easy to understand. It reads a DWORD from the encrypted data, rotates it left by 6 bit positions and XORs it with the XOR key 0x278C.
The resulting data is stored at the newly allocated heap at address, 0x0018F520:
As can be seen in the screenshot above, it is the MZ header of the malicious executable. However, it is not completely decrypted.
Unpacking the Custom Packer – Stage 2
Once the first decryption routine has completed, it proceeds to allocate a new heap, which will be used to store the final decrypted malicious executable:
Let’s check the second decryption routine at address, 0x00C5036E:
http://2we26u4fam7n16rz3a44uhbe1bq2.wpengin
Here is an explanation of the code with comments:
[CODE]PUSHAD
MOV ESI,DWORD PTR SS:[ESP+24]; source points to first stage of decryption
MOV EDI,DWORD PTR SS:[ESP+28]; points to newly allocated heap
CLD
MOV DL,80
XOR EBX,EBX
MOVS BYTEPTRES:[EDI],BYTEPTRDS:[ESI]; move one byte from source to destination
MOV BL,2
CALL 00C503F1
JNB SHORT00C5037C
XOR ECX,ECX
CALL 00C503F1
JNB SHORT00C503AB
XOR EAX,EAX
CALL00C503F1
JNB SHORT00C503BB
MOV BL,2
INC ECX
MOV AL,10
CALL00C503F1
ADC AL,AL
JNB SHORT00C5039D
JNZ SHORT00C503E7
STOS BYTEPTRES:[EDI]
JMP SHORT00C5037F
CALL00C503FD
SUB ECX,EBX
JNZ SHORT00C503C4
CALL00C503FB
JMP SHORT00C503E3
LODS BYTEPTRDS:[ESI]; move the byte from source into EAX
SHR EAX,1; shift right the value in EAX by one position
JE SHORT00C5040D exit the decryption routine ifthis value inEAX is 0
ADC ECX,ECX
JMP SHORT00C503E0
XCHG EAX,ECX[/CODE]
After this subroutine has completed, we will have the decrypted malicious executable at address, 0×00194780
[IMG]http://2we26u4fam7n16rz3a44uhbe1bq2.wpengine.netdna-cdn.com/wp-content/uploads/071613_2159_DeepDiveint29.png
This decrypted malicious executable is located at the address, 0×00194780
Self-Modification of Main Image Header
It is followed by a call to VirtualProtect to modify the protection of the first 0xC000 bytes at 0×400000 (ImageBaseAddress) to 0×40 which corresponds to PAGE_EXECUTE_READWRITE as shown below:
The stack parameters are:
Now it sets the first 0xC000 bytes at the ImageBaseAddress to null bytes (0×00). This is done because it will be overwritten with the contents of the decrypted malicious executable.
After this, it will copy the sections of the decrypted executable to the ImageBaseAddress one by one (PE header, .text, .rsrc, .reloc and so on):
Using the below Subroutine, it will get the SizeOfHeaders of the decrypted executable.
It then proceeds to copy the PE header from the decrypted executable to the ImageBaseAddress:
It proceeds in this way to copy the .text, .rsrc and .reloc sections one by one to the Image Base Address:
1.Copy 0×8400 bytes of .text section from the decrypted image to 0×401000
2.Copy 0×200 bytes of .rsrc section from the decrypted image to 0x40A000
3.Copy 0×200 bytes of .reloc section from the decrypted image to 0x40B000
Decrypted Malicious Executable
It then calls the AddressOfEntryPoint of the malicious executable:
Let’s now trace the code inside the malicious executable:
This section of code will first retrieve the addresses of following APIs:
1.NtQueryInformationProcess
2.ZwReadVirtualMemory
3.2ZwMapViewofSection
4.NtCreateSection
5.ZwResumeThread
It then proceeds to create a new process called svchost.exe in Suspended State (Process Creation Flag is set to 0×4):
Stack parameters:
Code Injection into New Process
This virus uses an interesting way to inject the malicious code in the newly created process and later resume the execution of it. Unlike most malwares which make use of WriteProcessMemory() to inject the code in the Process Address Space of a remote process, it does not call WriteProcessMemory() at all.
It also helps in bypassing certain security mechanisms where system drivers detect the code injection by monitoring WriteProcessMemory API invocations in user mode.
Once the new process is created, it queries the remote process to retrieve Process Information by calling ZwQueryInformationProcess API as shown below:
The stack parameters are:
The output will be stored at the memory address 0x0012FD9C. It uses this to get the Process Environment Block address of the remote process as shown below:
In this case, PEB of svchost.exe is at the address, 0x7FFDA000
It then proceeds to find the ImageBaseAddress of svchost.exe by reading the value at offset 0×8 in PEB
Stack parameters:
It reads 0×4 bytes from the address 0x7FFDA008 in the process address space of the svchost.exe process and stores it at 0x0012FD28 as shown below:
The ImageBaseAddress of svchost.exe is 0×10000000
It then proceeds to create a new section within itself using ZwCreateSection API:
Stack parameters:
The handle of the new section is stored at the address 0x0012FD94:
After this, it calls ZwMapViewOfSection to map the newly created section (handle, 0×150) in itself.
Stack parameters:
The base address of the mapped view of Section is stored at 0x0012FD30:
The address of the mapped view of section is: 0x00A20000. The size of mapped view is 0x7CA0.
It then proceeds to copy 0x7CA0 bytes from 0x004010B0 to the mapped view at 0x00A20000:
Once this is done, the mapped view contains the code of malicious subroutine:
It uses another call to ZwMapViewofSection to map its section (that has the code of malicious subroutine) into svchost.exe process:
Stack parameters:
Here, 0×150 is the handle of the section object and 0×154 is the handle of svchost.exe process.
The base address of the newly mapped view will be present at 0x0012FD30:
Our malicious subroutine has been mapped at the address 0x000C0000 in svchost.exe process address space.
In this way, even without using a call to WriteProcessMemory it was able to inject the code of malicious subroutine in process address space of svchost.exe.
It then calls VirtualAlloc to allocate memory in its own Process Address Space:
Stack parameters:
The new memory region is allocated at address, 0x00C60000
Modification of Original Entry Point in Remote Process
It proceeds with a call to ZwReadVirtualMemory to read the PE Header of svchost.exe process and store it at the newly allocated memory region, 0x00C60000
Stack parameters:
Once it has the PE Header of svchost.exe at address, 0x00C60000, it parses that to find the size of Image of svchost.exe process:
Stack parameters:
It reads 0×6000 bytes (SizeOfImage of svchost.exe) from the ImageBaseAddress of svchost.exe and stores at 0x00C60000 in its Process Address Space.
The original entry point was located previously and stored in [EBP-88]. The RVA of AddressOfEntryPoint of svchost.exe is 0×2509.
Let’s look at the disassembly of the code at Original Entry Point in svchost.exe at present:
It is important to note here. Most malwares in the recent past used GetThreadContext() and SetThreadContext() to modify the Original Entry Point of the Primary Thread which will be executed in the remote process to trigger the malicious code execution. In this case, it does not use calls to GetThreadContext() and SetThreadContext() APIs to modify the Original Entry Point at all.
It then proceeds to modify the code at original entry point using the code below:
Here is the explanation of the code with comments:
After modification, the disassembly of the code at the Original Entry Point looks like shown below:
As can be seen, the OEP is modified so that it jumps to the subroutine at address 0x0C0000 and executes it. 0xC0000 is the location at which the malicious subroutine was injected previously in svchost.exe process.
It then makes another call to ZwCreateSection to create a new section within itself with the section handle, 0xEC.
Then it calls ZwMapViewOfSection and maps this newly created section at the address, 0x00A30000.
Once this is done, it will copy the bytes from the previously modified PE header of svchost.exe to this location.
It then calls ZwMapViewOfSection once again to map the bytes at 0x00A30000 to the ImageBaseAddress of svchost.exe process as shown below:
Stack parameters:
Now, the modified PE header has been written to the process address space of svchost.exe
It then calls ZwResumeThread to resume the execution of primary thread in svchost.exe.
This Primary Thread executes from the Original Entry Point of svchost.exe. Since that was modified previously to redirect the execution to malicious injected subroutine, it proceeds to successfully execute the malicious code within the context of svchost.exe
Debugging the Remote Process
Once it calls ZwResumeThread the execution of malicious subroutine is resumed in the context of svchost.exe process. To be able to debug it we need to modify the Original Entry Point before the code is injected in svchost.exe process.
This is how the code can be patched.
Please note that the memory addresses in the steps below may differ from the analysis done before because this was a new debugging session. The algorithm remains the same.
1.It calls VirtualAlloc()to allocate a new memory region at 0x00C90000
2.It calls ZwReadVirtualMemory to read 0×1000 bytes from the svchost.exe process into the newly allocated memory region.
3.It then calls ZwReadVirtualMemory again to read SizeOfImage (0×6000) bytes from svchost.exe process into the newly allocated memory region at 0x00C90000.
4.It then creates a new section within itself by calling ZwCreateSection.
5.It maps the view of the newly created section by calling ZwMapViewOfSection which is mapped at the base address 0×01190000.
6.It then proceeds to modify the Original Entry Point in the newly allocated memory region.
7.After this, it copies 0×6000 bytes from the newly allocated memory region at 0x00C90000 to the mapped view at 0×01190000
8.We need to patch the bytes in the mapped view which will be mapped to the Original Entry Point in remote process. In our case, it will be the bytes at 0×01192509.
At present we have at address, 0×01192509
We will patch with EB FE which is a short relative cyclic jump as shown below:
9.It again calls ZwMapViewOfSection to map the section object to the remote process.
10,It then resumes the thread in remote process by calling ZwResumeThread. The original entry point in remote process will be 0×01002509. Since we patched the bytes before, the code execution will pause at the Original Entry Point.
We will now be able to attach our Debugger to svchost.exe process. Let us now patch the bytes at the Original Entry Point in remote process and restore them:
After patching, we set a breakpoint at the OEP and run, so that we break at the OEP:
Now we can proceed with debugging the malicious subroutine in svchost.exe process.
Conclusion
After reading this article you should be able to unpack malwares which use a similar technique to pack their code and prevent debugging.
It also allows us to see the new ways in which malware authors are trying to bypass the AV and prevent analysis of malwares.
sursa:
c0d3inj3cT July 17, 2013
Introduction
In this article we will look in depth at a Custom Packer used by a Malware that was recently found in the wild. This packer is interesting for several reasons. It uses several layers of packers including the well-known UPX Packer which is only used to mask the underlying custom packers.
It also uses a clever way of injecting code into a remote process and resuming its execution from there. I have included necessary screenshots with snippets of assembly language code sections along with comments, stack parameters for API calls and views of memory dump. This will help in following the article while the unpacking method is described.
An Overview
Since the unpacking method is described in depth and there are several layers, I am giving a high level overview of the algorithm at first before going in depth.
1.It uses a UPX packer which is used only for the purpose of masking the underlying custom packers. UPX packers as we know can be easily unpacked.
2.The first layer of a custom packer uses a lot of code which has been placed only to increase the size of code we have to go through while reversing. With the help of few example code snippets, this has been explained. It’s used to deter reverse engineering.
3.It stores the encrypted subroutine at a particular offset within itself. This subroutine is later decrypted and executed.
4.In the second stage, the decrypted subroutine performs another level of unpacking. There is an encrypted malicious executable embedded inside the main image which is decrypted in two phases.
5.After the decryption of the malicious executable, it proceeds to modify the header of the main image. It copies the various sections of the malicious executable like PE Header, .text, .rsrc, .reloc to the start of main image.
6.It then calls the AddressOfEntry point of the malicious executable. This code will spawn a new process, svchost.exe in a suspended state.
7,It then proceeds to inject the malicious code in svchost.exe process and resume its execution.
Unpack the UPX
This executable uses a clever way of packing. It uses a well-known packer called UPX which is detected by most automated sandboxes and packer identifiers like PEiD and ProtectorID.
So, we start by unpacking the UPX packer. As already known, UPX packers can be unpacked using the ESP + hardware breakpoint trick. So, let us unpack it using this method.
This is how the Original Entry Point of a UPX packed binary looks:

We step over the PUSHAD instruction which will save the contents of all the registers on the stack.
Once we step over PUSHAD, we will follow ESP in memory dump and set a Hardware Breakpoint at the WORD present at that memory location. The reason this is done is: once the unpacking completes, POPAD instruction will be executed that will restore the contents of registers.
As a result, this memory location will be accessed and modified. So, we set the hardware breakpoint as shown in the screenshot below:

Once we run the executable after setting the hardware breakpoint, we break at the following memory location:

Next, we set a breakpoint at 0x004170B4 to skip over the loop.

Once we step over this, we reach the Original Entry Point at 0×00402690.
In most cases, this is the unpacked executable and now you can start stepping through the code to understand the malware. So, let’s continue with that.
Identification of Unnecessary Code Sections
This is how our Original Entry Point at 0×00402690 looks like after unpacking UPX:

This looks good, so let’s continue.
After tracing the code further from OEP, we reach a CALL to the subroutine at address, 0×00401020.

In most cases, you would reach the code corresponding to malware after this. So, let’s see:

This subroutine contains a lot of code which has been placed to deter reverse engineering. For instance, if you check the section of code below:
It moves a constant DWORD into a memory location, [EBP-58] and then compares it with another constant DWORD, followed by a check for whether they are unequal. Since they will always be unequal, the Jump will be taken.
Similar lines of code were observed in multiple places in the subroutine which were added only to increase the size of code that we have to go through while reversing.
Similarly, another section of code:

It moves a constant DWORD into [EBP-54], and then moves it to EDX, multiplies with itself, and then adds it to the result and stores back in the memory address.
However, this value is not relevant to us for reversing.
Decryption of Custom Unpacking Subroutine
Proceeding in this way and skipping over sections of code that use code similar to above, we reach a CALL to VirtualAlloc with the stack parameters as shown below:

It allocates a new memory with a size of 0×1830 bytes.
It is important to note that, VirtualAlloc is a good way of locating the Original Entry Point of an executable. The reason being, while unpacking it’s common to see a CALL to VirtualAlloc which allocates a new memory region. Encrypted data is copied to this memory location and then decrypted.
If the data at this memory location is executed later on, then it means we have unpacked it or reached the original entry point (it’s possible that there is more code obfuscation later).
In our case, the call to VirtualAlloc() allocates a new memory region at base address, 0x00C50000

Tracing the code further we reach a CALL to subroutine at 0x004016F0 as shown below:

Tracing this subroutine further, we locate our first decryption routine:

The encrypted data is stored at memory address, 0×405028as shown below:

Here is a high level overview of the decryption subroutine:
1.It reads one DWORD at a time from the encrypted data.
2.It modifies the DWORD by passing it to a subroutine at 0x00401A80
3.The DWORD modified above is passed to a second subroutine at 0x004014E0
4.The final modified DWORD is written to the newly allocated memory region at 0x00C50000
5.There is a counter which is used to keep track of the number of DWORDs read from the Encrypted Data section. A total of 0x12A DWORDs are read, modified and written to the newly allocated memory region.
Below is the code explanation with comments:
Here is the first DWORD modification routine:

Here is an explanation of the code with comments:
The result of the first DWORD modification routine is passed to the second subroutine at: 0x004014E0

Here is the second DWORD modification routine:

Here is the code with comments:
After returning from the second subroutine, it will write this modified DWORD in the newly allocated memory region:

Here is an explanation of the code with comments:
Once the decryption has completed, we have the decrypted data present at 0x00C50000 as shown below:

Now, it calls the decrypted subroutine at 0x00C50000 as shown below:

Unpacking the Custom Packer – Stage 1
Once we step into this subroutine we are the first decrypted subroutine as shown below:

Here is an explanation of the code:
We will step into the first subroutine at 0x00C501FA which is used to get the address of different APIs:

Here is explanation of the code with comments:
It uses the subroutine at 0x00C502BF to get the base address of kernel32.dll by parsing the PEB structure. This is a common method used by shellcodes and various malwares to dynamically find the base address of kernel32.dll:

The next subroutine at address, 00C5030Eis used to get the address of GetProcAddress API which will later be used to get the address of different APIs.
It proceeds to find the address of different APIs using GetProcAddress as shown below:

All these function pointers are stored in memory, as shown below:

Now that it has retrieved the pointers to some APIs, it starts with another decryption routine.
The code of malicious executable is located at memory address, 0x004054D0

First, let’s take a look at this encrypted data:

If you look at this encrypted data, you will observe a pattern. After every DWORD, we have the WORDs 0×0050 or 0×0051 corresponding to ASCII values P. or Q. respectively.
Now, let’s check the decryption routine. It is mentioned below with comments:
This subroutine is easy to understand. It reads a DWORD from the encrypted data, rotates it left by 6 bit positions and XORs it with the XOR key 0x278C.
The resulting data is stored at the newly allocated heap at address, 0x0018F520:

As can be seen in the screenshot above, it is the MZ header of the malicious executable. However, it is not completely decrypted.
Unpacking the Custom Packer – Stage 2
Once the first decryption routine has completed, it proceeds to allocate a new heap, which will be used to store the final decrypted malicious executable:
Let’s check the second decryption routine at address, 0x00C5036E:
http://2we26u4fam7n16rz3a44uhbe1bq2.wpengin
Here is an explanation of the code with comments:
[CODE]PUSHAD
MOV ESI,DWORD PTR SS:[ESP+24]; source points to first stage of decryption
MOV EDI,DWORD PTR SS:[ESP+28]; points to newly allocated heap
CLD
MOV DL,80
XOR EBX,EBX
MOVS BYTEPTRES:[EDI],BYTEPTRDS:[ESI]; move one byte from source to destination
MOV BL,2
CALL 00C503F1
JNB SHORT00C5037C
XOR ECX,ECX
CALL 00C503F1
JNB SHORT00C503AB
XOR EAX,EAX
CALL00C503F1
JNB SHORT00C503BB
MOV BL,2
INC ECX
MOV AL,10
CALL00C503F1
ADC AL,AL
JNB SHORT00C5039D
JNZ SHORT00C503E7
STOS BYTEPTRES:[EDI]
JMP SHORT00C5037F
CALL00C503FD
SUB ECX,EBX
JNZ SHORT00C503C4
CALL00C503FB
JMP SHORT00C503E3
LODS BYTEPTRDS:[ESI]; move the byte from source into EAX
SHR EAX,1; shift right the value in EAX by one position
JE SHORT00C5040D exit the decryption routine ifthis value inEAX is 0
ADC ECX,ECX
JMP SHORT00C503E0
XCHG EAX,ECX[/CODE]
After this subroutine has completed, we will have the decrypted malicious executable at address, 0×00194780
[IMG]http://2we26u4fam7n16rz3a44uhbe1bq2.wpengine.netdna-cdn.com/wp-content/uploads/071613_2159_DeepDiveint29.png
This decrypted malicious executable is located at the address, 0×00194780
Self-Modification of Main Image Header
It is followed by a call to VirtualProtect to modify the protection of the first 0xC000 bytes at 0×400000 (ImageBaseAddress) to 0×40 which corresponds to PAGE_EXECUTE_READWRITE as shown below:

The stack parameters are:

Now it sets the first 0xC000 bytes at the ImageBaseAddress to null bytes (0×00). This is done because it will be overwritten with the contents of the decrypted malicious executable.
After this, it will copy the sections of the decrypted executable to the ImageBaseAddress one by one (PE header, .text, .rsrc, .reloc and so on):
Using the below Subroutine, it will get the SizeOfHeaders of the decrypted executable.
It then proceeds to copy the PE header from the decrypted executable to the ImageBaseAddress:
It proceeds in this way to copy the .text, .rsrc and .reloc sections one by one to the Image Base Address:
1.Copy 0×8400 bytes of .text section from the decrypted image to 0×401000
2.Copy 0×200 bytes of .rsrc section from the decrypted image to 0x40A000
3.Copy 0×200 bytes of .reloc section from the decrypted image to 0x40B000
Decrypted Malicious Executable
It then calls the AddressOfEntryPoint of the malicious executable:

Let’s now trace the code inside the malicious executable:

This section of code will first retrieve the addresses of following APIs:
1.NtQueryInformationProcess
2.ZwReadVirtualMemory
3.2ZwMapViewofSection
4.NtCreateSection
5.ZwResumeThread
It then proceeds to create a new process called svchost.exe in Suspended State (Process Creation Flag is set to 0×4):

Stack parameters:

Code Injection into New Process
This virus uses an interesting way to inject the malicious code in the newly created process and later resume the execution of it. Unlike most malwares which make use of WriteProcessMemory() to inject the code in the Process Address Space of a remote process, it does not call WriteProcessMemory() at all.
It also helps in bypassing certain security mechanisms where system drivers detect the code injection by monitoring WriteProcessMemory API invocations in user mode.
Once the new process is created, it queries the remote process to retrieve Process Information by calling ZwQueryInformationProcess API as shown below:

The stack parameters are:

The output will be stored at the memory address 0x0012FD9C. It uses this to get the Process Environment Block address of the remote process as shown below:

In this case, PEB of svchost.exe is at the address, 0x7FFDA000
It then proceeds to find the ImageBaseAddress of svchost.exe by reading the value at offset 0×8 in PEB

Stack parameters:

It reads 0×4 bytes from the address 0x7FFDA008 in the process address space of the svchost.exe process and stores it at 0x0012FD28 as shown below:

The ImageBaseAddress of svchost.exe is 0×10000000
It then proceeds to create a new section within itself using ZwCreateSection API:

Stack parameters:

The handle of the new section is stored at the address 0x0012FD94:

After this, it calls ZwMapViewOfSection to map the newly created section (handle, 0×150) in itself.

Stack parameters:

The base address of the mapped view of Section is stored at 0x0012FD30:

The address of the mapped view of section is: 0x00A20000. The size of mapped view is 0x7CA0.
It then proceeds to copy 0x7CA0 bytes from 0x004010B0 to the mapped view at 0x00A20000:

Once this is done, the mapped view contains the code of malicious subroutine:

It uses another call to ZwMapViewofSection to map its section (that has the code of malicious subroutine) into svchost.exe process:

Stack parameters:

Here, 0×150 is the handle of the section object and 0×154 is the handle of svchost.exe process.
The base address of the newly mapped view will be present at 0x0012FD30:

Our malicious subroutine has been mapped at the address 0x000C0000 in svchost.exe process address space.
In this way, even without using a call to WriteProcessMemory it was able to inject the code of malicious subroutine in process address space of svchost.exe.
It then calls VirtualAlloc to allocate memory in its own Process Address Space:

Stack parameters:

The new memory region is allocated at address, 0x00C60000

Modification of Original Entry Point in Remote Process
It proceeds with a call to ZwReadVirtualMemory to read the PE Header of svchost.exe process and store it at the newly allocated memory region, 0x00C60000

Stack parameters:

Once it has the PE Header of svchost.exe at address, 0x00C60000, it parses that to find the size of Image of svchost.exe process:

Stack parameters:

It reads 0×6000 bytes (SizeOfImage of svchost.exe) from the ImageBaseAddress of svchost.exe and stores at 0x00C60000 in its Process Address Space.
The original entry point was located previously and stored in [EBP-88]. The RVA of AddressOfEntryPoint of svchost.exe is 0×2509.
Let’s look at the disassembly of the code at Original Entry Point in svchost.exe at present:

It is important to note here. Most malwares in the recent past used GetThreadContext() and SetThreadContext() to modify the Original Entry Point of the Primary Thread which will be executed in the remote process to trigger the malicious code execution. In this case, it does not use calls to GetThreadContext() and SetThreadContext() APIs to modify the Original Entry Point at all.
It then proceeds to modify the code at original entry point using the code below:

Here is the explanation of the code with comments:
After modification, the disassembly of the code at the Original Entry Point looks like shown below:

As can be seen, the OEP is modified so that it jumps to the subroutine at address 0x0C0000 and executes it. 0xC0000 is the location at which the malicious subroutine was injected previously in svchost.exe process.
It then makes another call to ZwCreateSection to create a new section within itself with the section handle, 0xEC.
Then it calls ZwMapViewOfSection and maps this newly created section at the address, 0x00A30000.
Once this is done, it will copy the bytes from the previously modified PE header of svchost.exe to this location.

It then calls ZwMapViewOfSection once again to map the bytes at 0x00A30000 to the ImageBaseAddress of svchost.exe process as shown below:

Stack parameters:

Now, the modified PE header has been written to the process address space of svchost.exe
It then calls ZwResumeThread to resume the execution of primary thread in svchost.exe.

This Primary Thread executes from the Original Entry Point of svchost.exe. Since that was modified previously to redirect the execution to malicious injected subroutine, it proceeds to successfully execute the malicious code within the context of svchost.exe
Debugging the Remote Process
Once it calls ZwResumeThread the execution of malicious subroutine is resumed in the context of svchost.exe process. To be able to debug it we need to modify the Original Entry Point before the code is injected in svchost.exe process.
This is how the code can be patched.
Please note that the memory addresses in the steps below may differ from the analysis done before because this was a new debugging session. The algorithm remains the same.
1.It calls VirtualAlloc()to allocate a new memory region at 0x00C90000
2.It calls ZwReadVirtualMemory to read 0×1000 bytes from the svchost.exe process into the newly allocated memory region.
3.It then calls ZwReadVirtualMemory again to read SizeOfImage (0×6000) bytes from svchost.exe process into the newly allocated memory region at 0x00C90000.
4.It then creates a new section within itself by calling ZwCreateSection.
5.It maps the view of the newly created section by calling ZwMapViewOfSection which is mapped at the base address 0×01190000.
6.It then proceeds to modify the Original Entry Point in the newly allocated memory region.
7.After this, it copies 0×6000 bytes from the newly allocated memory region at 0x00C90000 to the mapped view at 0×01190000
8.We need to patch the bytes in the mapped view which will be mapped to the Original Entry Point in remote process. In our case, it will be the bytes at 0×01192509.
At present we have at address, 0×01192509
We will patch with EB FE which is a short relative cyclic jump as shown below:

9.It again calls ZwMapViewOfSection to map the section object to the remote process.
10,It then resumes the thread in remote process by calling ZwResumeThread. The original entry point in remote process will be 0×01002509. Since we patched the bytes before, the code execution will pause at the Original Entry Point.
We will now be able to attach our Debugger to svchost.exe process. Let us now patch the bytes at the Original Entry Point in remote process and restore them:

After patching, we set a breakpoint at the OEP and run, so that we break at the OEP:

Now we can proceed with debugging the malicious subroutine in svchost.exe process.
Conclusion
After reading this article you should be able to unpack malwares which use a similar technique to pack their code and prevent debugging.
It also allows us to see the new ways in which malware authors are trying to bypass the AV and prevent analysis of malwares.
sursa: