adding sections 3-5
BIN
RE102/images/Section3.1_PEstructure.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
RE102/images/Section3.1_VirtualAlloc.png
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
RE102/images/Section3.1_delphi2.gif
Normal file
|
After Width: | Height: | Size: 381 KiB |
BIN
RE102/images/Section3.1_junkstrings.gif
Normal file
|
After Width: | Height: | Size: 585 KiB |
BIN
RE102/images/Section3.1_record_interesting.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
RE102/images/Section3_array1.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
RE102/images/Section3_array2.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
RE102/images/Section3_delphi.gif
Normal file
|
After Width: | Height: | Size: 418 KiB |
BIN
RE102/images/Section3_initexe.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
RE102/images/Section4.1_256bytes.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
RE102/images/Section4.1_TheStackFrame2.png
Normal file
|
After Width: | Height: | Size: 111 KiB |
BIN
RE102/images/Section4.1_keyschedule.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
RE102/images/Section4.1_loop1.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
RE102/images/Section4.1_loop2.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
RE102/images/Section4.1_loop3.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
RE102/images/Section4.2_HxDextract.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
RE102/images/Section4.2_ReturnAddress.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
RE102/images/Section4.2_error.gif
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
RE102/images/Section4_cipher.png
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
RE102/images/Section4_functionargs.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
RE102/images/Section4_looping.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
RE102/images/Section5.1_4019E4.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
RE102/images/Section5.1_405272.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
RE102/images/Section5.1_LoadResource.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
RE102/images/Section5.1_Virtualloc318.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
RE102/images/Section5.1_allocate318.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
RE102/images/Section5.1_breakpoint.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
RE102/images/Section5.1_resource.png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
BIN
RE102/images/Section5.1_savingresource.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
RE102/images/Section5.2_Hardware2.gif
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
BIN
RE102/images/Section5.2_ModifyFlags.gif
Normal file
|
After Width: | Height: | Size: 4.2 MiB |
BIN
RE102/images/Section5.2_ModifyJump2.gif
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
BIN
RE102/images/Section5.2_PhysicalDriveapicall.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
RE102/images/Section5.2_biosjump.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
RE102/images/Section5.2_biosjump2.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
RE102/images/Section5.2_checkbypass.png
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
RE102/images/Section5.2_checkregistry.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
RE102/images/Section5.2_deviceIOcontroljump.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
RE102/images/Section5.2_hardware.gif
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
RE102/images/Section5.2_hardwarestrings.png
Normal file
|
After Width: | Height: | Size: 107 KiB |
BIN
RE102/images/Section5.2_sandboxiedll.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
RE102/images/Section5.2_systembiosregistry.png
Normal file
|
After Width: | Height: | Size: 148 KiB |
BIN
RE102/images/Section5.2_vboxstoragesettings.png
Normal file
|
After Width: | Height: | Size: 120 KiB |
BIN
RE102/images/Section5_ControlFlowObfuscation.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
RE102/images/Section5_FunkyStrings.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
RE102/images/Section5_NameCheck.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
RE102/images/Section5_PEB.gif
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
RE102/images/Section5_PostStrings.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
RE102/images/Section5_checkname.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 1.9 MiB |
BIN
RE102/images/Section5_startdebugging.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
RE102/images/face.jpg
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
70
RE102/re102_section3.1.md
Normal file
@@ -0,0 +1,70 @@
|
||||
---
|
||||
layout: default
|
||||
permalink: /RE102/section3.1/
|
||||
title: Setup
|
||||
---
|
||||
[Go Back to Reverse Engineering Malware 102](https://securedorg.github.io/RE102/)
|
||||
|
||||
# Section 3.1: Lab 1 #
|
||||
|
||||
Go ahead and open IDAfree and load the malware. Give IDA some time to parse all of the functions. It should begin the analysis in the start function. If you are not in the start function, select the start function from the function tab/window.
|
||||
|
||||
## Identifying Delphi ##
|
||||
|
||||
The previous page talked about the delphi structure. Note: IDAPro provides better delphi library support and will automatically name library references for you. You should be able to identify the InitExe and the array of classes at offset [dword](https://msdn.microsoft.com/en-us/library/cc230318.aspx?f=255&MSPPError=-2147217396) at `0045BB5C`. Double-click on offset `dword_45BB5C`. Notice that this looks like the array discussed on the previous page.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Junk Data ##
|
||||
|
||||
In the information gathering stage, the strings revealed that there was some junk data being referenced. Let’s actually look how those strings are being referenced in the disassembler. Scroll down until you see some junk strings in the DATA section in the IDA Strings panel. Each Portable Executable (PE) section has its own purpose. The DATA (.data) section is typically used for hardcoded global and static variables that were initialized at compile time [1]. This section is more commonly used for storing string references. To see a string referenced in the data section that looks like junk data might be an indicator of foul play.
|
||||
|
||||
[1](https://msdn.microsoft.com/en-us/library/ms809762.aspx?f=255&MSPPError=-2147217396)
|
||||
|
||||
## Follow the Junk Data ##
|
||||
|
||||
Double-Click the first instance of the junk data. At this point is should show you the location in the IDA View. Scroll up until you see a `unk` reference to the start of this data. It should say `unk_45CCD4`. You want to follow this reference in the code by selecting and then press ‘x’ to open the xrefs menu. This menu shows all the functions and locations that reference the object. Select the only function present and press `ok`.
|
||||
|
||||

|
||||
|
||||
IDA should have landed you in the function that is using this data. Notice anything fishy about this function?
|
||||
|
||||

|
||||
|
||||
It’s calling `VirtualAlloc`.
|
||||
|
||||
So you see that VirtualAlloc with size 0x65E4 hex which is 26,084 bytes decimal. The junk data pointer (labeled Junk 2) is about to be used by function `sub_407074`. Normally when you see a function following VirtualAlloc, it will copy data into the newly created memory location. You should record the contents of Junk 1 because you will need this dword value later. Finally rename function `sub_407074` to something like “copy_to_new_mem”.
|
||||
|
||||

|
||||
|
||||
## Trace Backwards ##
|
||||
|
||||
So now you want to find the route between the **start** function and our renamed function **copy_to_new_mem**. By using xrefs (selecting & pressing x) you can follow all the functions that referenced the function you selected. Scroll up to the top of the functions and see if you can work your way back to the delphi class library array.
|
||||
|
||||
Your notes should be something like this:
|
||||
|
||||
`Copy_to_new_mem <- sub_45B794 <- sub_45B894 <- sub_45B93C <- 045BB5C (Array)`
|
||||
|
||||
Renaming each to something notable like:
|
||||
|
||||
`Copy_to_new_mem <- use_junkdata <- before_use_junkdata <- main_function <- 045BB5C (Array)`
|
||||
|
||||
Keeping track of this route by the function offset (e.g. `0045B93C`) allows you to set breakpoints when you start debugging. You know ahead of time where you want to navigate to.
|
||||
|
||||
## Recording Control Flow ##
|
||||
|
||||
IDA does a lovely job of showing you green and red arrows for control flow instructions in the assembly. You will want to keep track of instructions like cmp, jmp, jnz, jz, jl, jnb, etc. that affect the route. Recording these locations will come in handy when you start debugging and need to manipulate EFlags to change the decision of the jump.
|
||||
|
||||
## Record Anything Interesting ##
|
||||
|
||||
As you are building your route, any API call or string is helpful in identifying the purpose of a function. You may change the name of the function depending on what new information you find. For instance, `sub_45B93C` (a.k.a. main_function) is doing an interesting routine. Can you guess why this function is using GetForegroundWindow, Sleep, then GetForegroundWindow? If not, record and save it for later (Hint: Answer is in Section 5). These routines may affect the control flow instructions. The example below shows how the success or failure of OutputDebugStringA is compared using `cmp esi,ebx` while `jz` will jump if the result of the comparison is equal to zero. During debugging you may want to manipulate the EFlags so that it will not jump.
|
||||
|
||||

|
||||
|
||||
## Work on Your Own ##
|
||||
|
||||
Take this time to make some nice travel directions. The next page will have what your directions should look like.
|
||||
|
||||
[Section 3 <- Back](https://securedorg.github.io/RE102/section3) | [Next -> Section 3.2](https://securedorg.github.io/RE102/section3.2)
|
||||
41
RE102/re102_section3.2.md
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
layout: default
|
||||
permalink: /RE102/section3.2/
|
||||
title: Setup
|
||||
---
|
||||
[Go Back to Reverse Engineering Malware 102](https://securedorg.github.io/RE102/)
|
||||
|
||||
# Section 3.2: Travel Directions #
|
||||
|
||||
1. Start
|
||||
2. `sub_406604` - Step into InitExe
|
||||
3. `sub_403FA0` - Step into StartExe
|
||||
4. `sub_403F40` - Step into This loops through the static list of functions in the references until the main function sub_45B93C
|
||||
5. `sub_45B93C` - Checks to see if the foreground window has changed
|
||||
1. First it will get the foreground window, then sleep for 64h then capture the foreground window again (See Section 5)
|
||||
2. `0045B991` - jz should not jump
|
||||
6. It then tries to check for debug output using string “w4ZUHcHjWZiye735mOUvnkKZ6XwjXIlyrS” (See Section 5)
|
||||
1. `0045B9C1` - jl should jump
|
||||
2. `0045B9CB` - jnz should not jump
|
||||
7. Tries to unsuccessfully load dll AXLzZmdD9HtbQccvaUl8.dll
|
||||
1. `0045B9D9` - jnz should not jump
|
||||
2. `0045B9DE` - jnz should not jump
|
||||
8. Tries to find Atom RkLNPKJEBsQUb
|
||||
9. `sub_45B894` - Step into before_use_junkdata
|
||||
1. `GetConsoleCP` - Retrieves the input code page used by the console associated with the calling process. A console uses its input code page to translate keyboard input into the corresponding character value.
|
||||
2. `0045B89F` - jz should not jump
|
||||
3. Loops for 0x355aef09 times for no reason. Kill the loop by `0045B8AD` jnz to not jump.
|
||||
4. `0045B8C4` - jnz should not jump
|
||||
5. Loops for 0x5A73350 times for no reason. Kill the loop by setting jnz to not jump.
|
||||
10. `sub_45B794` - Step into use_junkdata
|
||||
1. VirtualAlloc new memory with the size of 0x65E4
|
||||
2. Nop instructions indicate foul play (See Section 5)
|
||||
3. `dword_45CCB0` value is 0x42B7
|
||||
4. `unk_45CCD4` is the Junk data
|
||||
5. `sub_407074` - Step over Copy_to_new_mem, loads Junk data of size 65E4 into new memory: Delphi move(source, dest);
|
||||
6. `unk_45CCB4` - loads 0x20 byte string
|
||||
7. `sub_45B5AC` - do_something_interesting( size of junk data, size of 0x20 byte string, pointer to 0x20 byte string, 0x100, 0x0BEE2, pointer to newly copied memory of junk data)
|
||||
|
||||
Let’s save `sub_45B5AC` for the next section.
|
||||
|
||||
[Section 3.1 <- Back](https://securedorg.github.io/RE102/section3.1) | [Next -> Section 4](https://securedorg.github.io/RE102/section4)
|
||||
44
RE102/re102_section3.md
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
layout: default
|
||||
permalink: /RE102/section3/
|
||||
title: Setup
|
||||
---
|
||||
[Go Back to Reverse Engineering Malware 102](https://securedorg.github.io/RE102/)
|
||||
|
||||
# Section 3: Creating Travel Directions #
|
||||
|
||||

|
||||
|
||||
Now it's time for static analysis by looking at the disassembly. The point of this section is to create a map of the execution flow of the malware. The easiest way to accomplish this is by starting somewhere in the middle and then working your way backwards. Working backwards helps you create a more accurate route because you can see the forks that led to your current position. You can anticipate the right or left path, in assembly, it’s jump or not-to-jump.
|
||||
|
||||
Starting somewhere in the middle means picking an interesting function to look at or where a string is referenced. Many malware reverse engineers want to start at interesting API functions like the imports mentioned in Section 2.
|
||||
|
||||
## Understanding Post-Compiled Structure ##
|
||||
|
||||
Remember that this sample is Borland Delphi code. This means we will see many functions building up the Delphi libraries. These libraries are organized like object-oriented classes. Each class has an initialization function as well as references to class functions. A Delphi app will sequentially load these structures where libraries are loaded before the main function coded by the malware author. Makes sense, right? In order to use the library, you have to load them first.
|
||||
|
||||

|
||||
|
||||
The diagram above is a high-level view of how a Delphi app executes each library class. There is a pointer to a hardcoded array/list of these classes which is passed to InitExe function and then the StartExe function. It will loop through this list initializing, executing, and storing pointers to functions for later use. I have identified Main Functions as the possible interesting functions we want to look at. Below the is the disassembly equivalent of the diagram.
|
||||
|
||||
*Click Image to Enlarge*
|
||||
[](https://securedorg.github.io/RE102/images/Section3_initexe.png)
|
||||
|
||||
*Click Image to Enlarge*
|
||||
[](https://securedorg.github.io/RE102/images/Section3_array1.png)
|
||||
[](https://securedorg.github.io/RE102/images/Section3_array1.png)
|
||||
|
||||
---
|
||||
|
||||
## Where to Start? ##
|
||||
|
||||
So we have some options to start working backwards:
|
||||
|
||||
1. Where was that junk data was referenced.
|
||||
2. Choose an import function (i.e VirtualAlloc).
|
||||
3. Choose a function that is not loading a library.
|
||||
|
||||
So the goal here is making the route between the StartExe and choices 1,2, or 3. So let’s pick option 1 and start Lab 1 on the next page.
|
||||
|
||||
|
||||
[Section 2.1 <- Back](https://securedorg.github.io/RE102/section2.1) | [Next -> Section 3.1](https://securedorg.github.io/RE102/section3.1)
|
||||
159
RE102/re102_section4.1.md
Normal file
@@ -0,0 +1,159 @@
|
||||
---
|
||||
layout: default
|
||||
permalink: /RE102/section4.1/
|
||||
title: Setup
|
||||
---
|
||||
[Go Back to Reverse Engineering Malware 102](https://securedorg.github.io/RE102/)
|
||||
|
||||
# Section 4.1: Identifying the Decryption Algorithm #
|
||||
|
||||
Now it’s time to dig deeper and follow the assembly one step at a time. From the previous page you recorded what are the arguments and variables used in function `sub_45B5AC`:
|
||||
|
||||
```
|
||||
eax = data_size
|
||||
edx= key_size
|
||||
ecx = key
|
||||
sub_45B5AC( 0x100, 0xBEE2, junk2, 0x1F)
|
||||
```
|
||||
|
||||
Now that you are in the `sub_45B5AC` function, IDA labels the arguments as:
|
||||
|
||||
```
|
||||
Arg_0 = 0x100
|
||||
Arg_4 = 0xBEE2
|
||||
Arg_8 = junk2
|
||||
Arg_C = 0x1F
|
||||
```
|
||||
|
||||
At loc_45B5C9, the registers that saved the key and sizes are moved into base pointer offsets:
|
||||
|
||||
```
|
||||
45b5cb: mov [ebp-0xc], ecx ; Key
|
||||
45b5ce: mov [ebp-0x8], edx ; Size of Key
|
||||
45b5d1: mov [ebp-0x4], eax ; Size of Shellcode
|
||||
```
|
||||
|
||||
Remember the stack structure from RE101, local variables grow to lower addresses and parameters grow to higher addresses:
|
||||
|
||||

|
||||
|
||||
Now that you have all the important variables, you can statically trace through this function in IDA to discover it’s algorithm.
|
||||
|
||||
---
|
||||
|
||||
## Loop 1: Saving the Key on the Stack ##
|
||||
|
||||
Arg_C is 0x1F (31 dec) bytes, which is one byte less than the size of our key. Since arrays start from 0, as you can guess this represents **key_size - 1**. This gets saved into register `ebx`
|
||||
|
||||

|
||||
|
||||
If you are not familiar with mathematical equivalent of bitwise operations, it is important to know shift operations can be a form of multiplication or division. For example, when you see `shr ebx, 2`, it means that the content of the ebx register is getting divided by 4. This is 31 divided by 4. Why 4? Because when you shift n bits of an unsigned binary number, it has the effect of dividing it by 2^n (rounding towards 0). As it loops through the Key (ecx) is pushes/saves 4 byte chunks onto the stack. It should look something like this:
|
||||
|
||||
```
|
||||
00183BCC 3669C7AF
|
||||
00183BD0 CBD60266
|
||||
00183BD4 0C33A849
|
||||
00183BD8 973AD4C1
|
||||
00183BDC C868B780
|
||||
00183BE0 820B3D00
|
||||
00183BE4 2C9BED2C
|
||||
00183BE8 F94D125D
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Loop 2: Fill the Stack 0x100 characters
|
||||
|
||||
This next loop fills the stack starting at `[ebp+var_418]`. It loops for 0x100 times or 256 decimal while incrementing ebx from 0 to 255.
|
||||
|
||||

|
||||
|
||||
At this stage the question that you need to ask yourself is what crypto algorithm uses 256 bytes with a key size of 32 bytes? You can also even narrow it down to only symmetric key algorithms, since this function is way too simple be an asymmetric key algorithm.
|
||||
|
||||
So let’s create the pseudo code for this loop:
|
||||
|
||||
```
|
||||
int ebx = 0;
|
||||
int length = 265 // 0x100
|
||||
While (ebx < 256)
|
||||
{
|
||||
push(i)
|
||||
ebx++
|
||||
}
|
||||
```
|
||||
|
||||
This is what the stack should look like:
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Loop 3: Functions applied to 0x100 characters ##
|
||||
|
||||
In the same location on the stack [ebp+var_418], the loop processes the data again, but introduces the usage of function `sub_405268`. This function takes 3 inputs.
|
||||
|
||||
The first call to `sub_405268`:
|
||||
|
||||
1. 0
|
||||
2. [ebp-0x8] Size of Key which is 32 decimal
|
||||
3. eax
|
||||
|
||||
The second call to `sub_405268`:
|
||||
|
||||
1. 0
|
||||
2. Arg_0 which is 0x100, 256 decimal
|
||||
3. eax
|
||||
|
||||

|
||||
|
||||
When you enter function sub_405268, you will notice that there are a bunch of arithmetic instructions. This function is actually a modulo function. Tip: the Pro version of IDA marks function sub_405268 as the Delphi library function System::llmod.
|
||||
|
||||
Rename function `sub_405268` to “mod”.
|
||||
|
||||
At the end of the loop, the are some move instructions. Can you guess what is going on here?
|
||||
|
||||
* `ebx` is being incremented by 1, let ebx be i where i = 0
|
||||
* `esi` is being incremented by 4, in other words let esi be j where j = 0.
|
||||
* `[ebp+var_418]` is location of the 0-256 characters created, let it be array[]
|
||||
* `ebp+var_C` is the pointer to the Key
|
||||
* `ebp+var_D` is a temporary location on the stack
|
||||
|
||||
So let’s make the pseudo code for this loop:
|
||||
|
||||
```
|
||||
int i = 0; //eax
|
||||
int j = 0;
|
||||
int temp, a, b, c;
|
||||
while (i < 0x100)
|
||||
{
|
||||
i = mod( 0, 0x20, i );
|
||||
a = Key[ i ]; // eax, [edx+eax]
|
||||
b = j+Array[i]; // edi, [esi]
|
||||
c = a+b; // add eax, edi
|
||||
j = mod (0, 0x100, c);
|
||||
|
||||
//swap
|
||||
temp = Array[i];
|
||||
Array[i] = Array[j];
|
||||
Array[j] = temp;
|
||||
i++;
|
||||
}
|
||||
```
|
||||
|
||||
Let’s see if you can identify this crypto algorithm. Try google searching for “symmetric mod 256”. Your first hit might be RC4 from wikipedia.
|
||||
|
||||

|
||||
|
||||
Check out that Key-scheduling algorithm on the RC4 wikipedia page. Notice any similarities from Loop 2 and Loop 3?
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Loop 4: Loop through Junk2 data ##
|
||||
|
||||
Looks like this algorithm is RC4 256. On your own, try to trace through the second part of the RC4 algorithm with the fourth loop. Be extra careful in assigning the variables, because there is an error here and you may not find it right away until you start decrypting.
|
||||
|
||||
Section 4.2 will go over decrypting that junk2 data.
|
||||
|
||||
[Section 4 <- Back](https://securedorg.github.io/RE102/section4) | [Next -> Section 4.2](https://securedorg.github.io/RE102/section4.2)
|
||||
130
RE102/re102_section4.2.md
Normal file
@@ -0,0 +1,130 @@
|
||||
---
|
||||
layout: default
|
||||
permalink: /RE102/section4.2/
|
||||
title: Setup
|
||||
---
|
||||
[Go Back to Reverse Engineering Malware 102](https://securedorg.github.io/RE102/)
|
||||
|
||||
# Section 4.2: Writing a Decryptor #
|
||||
|
||||
## The Return Address ##
|
||||
|
||||
Before you begin to decrypt the Junk2 data, let’s first jump back to the function that calls the decryption function in `sub_45B794`. Remember that dword that you saved earlier in the road map? The value 0x4B27 was added to the address of the newly allocated memort from VirtualAlloc. This value Offset+0x4B27 is being saved in register `esi` and then **pushed** onto the stack before the function returns. Typically functions will **pop** the `ebp` on the stack to return to the stack frame of the calling function. Here the eip will return to Offset+42B7 which is where our decrypted junk2 data will be.
|
||||
|
||||
You should recognize that the malware plans to execute the encrypted Junk2 data here. Now you know the purpose of the Junk2 data which is Position Independent Code (PIC) more typically known as Shellcode.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Export the Key and Shellcode ##
|
||||
|
||||
Now you need to export the Key and Shellcode bytes from the malware. You can use the HxD hex editor to extract this data.
|
||||
|
||||
In IDA, if you select the shellcode aka `unk_45CCD4` its offset is 0x5BED4. You know that the size of this data is 0x65E4. Open the mbam.exe with HxD and choose **Edit->Select Block**. Plug in the offset and length.
|
||||
|
||||

|
||||
|
||||
Copy and save these bytes into a new binary file in HxD hex editor and name it **shellcode.bin**.
|
||||
|
||||
Do the same for the Key offset and name it as **key.bin**.
|
||||
|
||||
---
|
||||
|
||||
## RC4 Decrypt Script ##
|
||||
|
||||
Let’s code the RC4 Stream Algorithm in python based on the pseudo code:
|
||||
|
||||
### Key Schedule Pseudo Code [1](https://en.wikipedia.org/wiki/RC4#Key-scheduling_algorithm_.28KSA.29) ###
|
||||
|
||||
```
|
||||
for i from 0 to 255
|
||||
S[i] := i
|
||||
endfor
|
||||
j := 0
|
||||
for i from 0 to 255
|
||||
j := (j + S[i] + key[i mod keylength]) mod 256
|
||||
swap values of S[i] and S[j]
|
||||
endfor
|
||||
```
|
||||
|
||||
### Pseudo-random generation algorithm (PRGA) [2](https://en.wikipedia.org/wiki/RC4#Pseudo-random_generation_algorithm_.28PRGA.29) ###
|
||||
|
||||
```
|
||||
i := 0
|
||||
j := 0
|
||||
while GeneratingOutput:
|
||||
i := (i + 1) mod 256
|
||||
j := (j + S[i]) mod 256
|
||||
swap values of S[i] and S[j]
|
||||
K := S[(S[i] + S[j]) mod 256]
|
||||
output K
|
||||
endwhile
|
||||
```
|
||||
|
||||
### Python Code ###
|
||||
|
||||
Here is the python code that mirrors the pseudo code above.
|
||||
|
||||
```
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def key_schedule(key):
|
||||
keylength = len(key)
|
||||
S = range(256)
|
||||
j = 0
|
||||
for i in range(256):
|
||||
k = ord(key[i % keylength])
|
||||
j = (j + S[i] + k) % 256
|
||||
S[i], S[j] = S[j], S[i] # swap
|
||||
return S
|
||||
|
||||
|
||||
with open(sys.argv[1], 'rb') as key_file, open(sys.argv[2], 'rb') as encrypted, open("decrypted_shellcode.bin", 'wb') as out:
|
||||
key_size = os.path.getsize(sys.argv[1]) # 0x20
|
||||
key = key_file.read(key_size)
|
||||
S = key_schedule(key)
|
||||
|
||||
j = 0
|
||||
i = 0
|
||||
|
||||
shellcode_size = os.path.getsize(sys.argv[2]) # 0x65E4
|
||||
|
||||
while (shellcode_size > 0):
|
||||
char = encrypted.read(1)
|
||||
i = (i + 1) % 256
|
||||
j = (j + S[i]) % 256
|
||||
|
||||
# swap
|
||||
S[i], S[j] = S[j], S[i]
|
||||
k = S[(S[i] + S[j]) % 256]
|
||||
shellcode_size -= 1
|
||||
|
||||
out.write(chr(ord(char) ^ k))
|
||||
out.close()
|
||||
key_file.close()
|
||||
encrypted.close()
|
||||
```
|
||||
|
||||
## Error in the Malware’s Decryption Algorithm! ##
|
||||
|
||||

|
||||
|
||||
If you run the script above you will get some terribly decrypted data. Why? Because there is an error in the RC4 algorithm implemented by the malware author. Between Loop 3 and Loop 4 the register that stores the j variable was not reseted after the key schedule is made.
|
||||
|
||||
## Run the Correct Decrypt Algorithm ##
|
||||
|
||||
This python script has the correct decryption algorithm.
|
||||
[decrypt_shellcode.py](https:\\securedorg.github.io/RE102/decrypt_shellcode.py)
|
||||
|
||||
|
||||
In the Victim VM, open up the command prompt and run the following line. Replace location to the folder you stored the bin files and script.
|
||||
```
|
||||
c:\Python27\python.exe <location>\decrypt_shellcode.py <location>\key.bin <location>\shellcode.bin
|
||||
```
|
||||
|
||||
Now that you have the decrypted shellcode let’s turn it into an exe so you can analyze it in IDA. The next page will provide these instructions.
|
||||
|
||||
[Section 4.1 <- Back](https://securedorg.github.io/RE102/section4.1) | [Next -> Section 4.3](https://securedorg.github.io/RE102/section4.3)
|
||||
56
RE102/re102_section4.3.md
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
layout: default
|
||||
permalink: /RE102/section4.3/
|
||||
title: Setup
|
||||
---
|
||||
[Go Back to Reverse Engineering Malware 102](https://securedorg.github.io/RE102/)
|
||||
|
||||
# Section 4.3: Convert the Shellcode Into an Exe #
|
||||
|
||||
Now you have the decrypted shellcode. This section will go over converting the shellcode into an executable so that you can view the disassembly in IDA.
|
||||
|
||||
Keep in mind that you don’t need to do this step, but converting it to an exe will help in debugging and viewing Evasion Techniques in Section 5. You can open the decrypted_shellcode.bin in IDA and notice that the disassembly is not parsing functions properly. The malware author has inserted extraneous assembly instructions to through off malware analysis. 0x78 means assembly instruction `js` or `Jump short if sign (SF=1)`.
|
||||
|
||||
```
|
||||
00000000: 7878 7878 7878 7878 7878 7878 7878 7878 xxxxxxxxxxxxxxxx
|
||||
00000010: 8b45 088b 4034 55e9 6761 0000 786a 6866 .E..@4U.ga..xjhf
|
||||
00000020: 8995 34ff ffff 5a6a 7266 8995 36ff ffff ..4...Zjrf..6...
|
||||
00000030: 5ae9 2506 0000 7878 7878 7878 7878 7878 Z.%...xxxxxxxxxx
|
||||
00000040: 7878 7878 7878 7858 6a74 6689 45c8 58e9 xxxxxxxXjtf.E.X.
|
||||
00000050: 0229 0000 7878 7878 7878 7878 7878 7878 .)..xxxxxxxxxxxx
|
||||
00000060: 7878 7878 7878 7889 5d88 e8af 3b00 0081 xxxxxxx.]...;...
|
||||
...
|
||||
```
|
||||
|
||||
There are many tools and scripts available that help you convert shellcode into an exe like [shellcode2exe.py](https://github.com/securedorg/shellcode_tools/blob/master/shellcode2exe.py). However I have found that Hexacon provided a nice easy [tutorial for converting shellcode into an executable](http://www.hexacorn.com/blog/2015/12/10/converting-shellcode-to-portable-executable-32-and-64-bit/). This section will be using this YASM and GoLink to create the executable while using CFF explorer to edit the binary header.
|
||||
|
||||
1. Download Yasm
|
||||
[http://www.tortall.net/projects/yasm/releases/yasm-1.3.0-win32.exe](http://www.tortall.net/projects/yasm/releases/yasm-1.3.0-win32.exe)
|
||||
2. Extract **yasm-1.3.0-win32.exe** and rename it to **yasm.exe**
|
||||
3. Download GoLink linker
|
||||
[http://www.godevtool.com/Golink.zip](http://www.godevtool.com/Golink.zip)
|
||||
4. Extract golink.exe
|
||||
5. Create a **decrypted_shellcode.asm** file with the following instructions
|
||||
|
||||
```
|
||||
Global Start
|
||||
SECTION 'AyyLmao' write, execute,read
|
||||
Start:
|
||||
incbin "decrypted_shellcode.bin"
|
||||
```
|
||||
6.From a command line run the following command to assemble the code:
|
||||
|
||||
```
|
||||
yasm.exe -f win32 -o decrypted_shellcode.obj decrypted_shellcode.asm
|
||||
```
|
||||
|
||||
7. Now run the linker
|
||||
|
||||
```
|
||||
golink /ni /entry Start decrypted_shellcode.obj
|
||||
```
|
||||
8. Open shellcode.exe with CFF explorer and open the NT Headers->Optional Headers->AddressOfEntryPoint. Add the current value to 0x4B27 which was the offset of where the malware was going to return to in function `sub_45B794`. AddressOfEntryPoint should be `000052B7`. This will ensure that IDA knows where to start the disassembly.
|
||||
|
||||
Finally, open the decrypted_shellcode.exe into IDA for Section 5.
|
||||
|
||||
[Section 4.2 <- Back](https://securedorg.github.io/RE102/section4.2) | [Next -> Section 5](https://securedorg.github.io/RE102/section5)
|
||||
87
RE102/re102_section4.md
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
layout: default
|
||||
permalink: /RE102/section4/
|
||||
title: Setup
|
||||
---
|
||||
[Go Back to Reverse Engineering Malware 102](https://securedorg.github.io/RE102/)
|
||||
|
||||
# Section 4: Identifying Encryption #
|
||||
|
||||

|
||||
|
||||
This section will focus on generically recognizing encryption routines. In the previous section, you left off at `sub_45B5AC`. As you might be able to guess, this malware is using an encryption algorithm here. The give aways are:
|
||||
|
||||
* Suspicious function arguments (e.g., large amounts of bytes used for allocation)
|
||||
* Multiple loops
|
||||
* Usage of XOR
|
||||
* Unusual instructions (e.g., NOP)
|
||||
|
||||
---
|
||||
|
||||
## Suspicious Function Arguments ##
|
||||
|
||||
To decrypt data that is encrypted the malware needs:
|
||||
|
||||
1. Key
|
||||
2. Encrypted Data (a.k.a ciphertext)
|
||||
3. Destination for Decrypted Data
|
||||
|
||||
Let’s take a look at the arguments for `sub_45B5AC`. Remember in section 1.3 of RE 101, it explained that assembly function calls have their arguments pushed onto the stack in reverse order. To learn about the reason behind this you can check out this [article](https://en.wikipedia.org/wiki/Calling_convention). In the image below, you can see it’s pushing 4 times and saving 3 objects in 3 different registers (ecx, edx, eax).
|
||||
|
||||

|
||||
|
||||
Based on previous sections, it should be already obvious to you what these values mean. You know that the malware recently called VirtualAlloc, and moved **junk 2** of size 0x65E4 into the new memory stored it in `[ebp+var_BEEB]`. If you click on `unk_45CCB4`, you will see that this data is only 0x20 (32 dec) bytes. So, the pseudo code for this function would be:
|
||||
|
||||
```
|
||||
eax = size_of_junk2
|
||||
edx = size_of_small_junk
|
||||
ecx = small_junk unk_45CCB4
|
||||
sub_45B5AC( 0x100, 0xBEE2, junk2, 0x1F)
|
||||
```
|
||||
|
||||
Let’s rename it all:
|
||||
|
||||
```
|
||||
eax = data_size
|
||||
edx= key_size
|
||||
ecx = key
|
||||
decrypt(0x100, 0xBEE2, encrypted_data, 0x1F)
|
||||
```
|
||||
|
||||
Now all you need to know is what 0x100 and 0xBEE2 represent, and you might not know until you start to break down the decrypt function.
|
||||
|
||||
**Hint:** 0xBEE2 is 48,866 bytes. This is large enough to be a new executable.
|
||||
|
||||
---
|
||||
|
||||
## Multiple Loops ##
|
||||
|
||||
Cryptographic algorithms are often grouped into two major categories: symmetric and asymmetric. Most of these algorithms in order to perform some sort of shuffling to the plaintext need to loop over each or blocks of characters. Let’s take a look at a structure used in many symmetric block cipher algorithms:
|
||||
|
||||

|
||||
|
||||
For every subkey K in this algorithm, it has to loop through each K to XOR and Swap. In the disassembly you will be able to see this looping, incrementing, and swapping action going on. Now let’s look at sub_45B5AC.
|
||||
|
||||

|
||||
|
||||
There are actually multiple loops happening in this function. Section 4.1 will go over how identifying this algorithm. This section focuses on just recognizing usage of crypto.
|
||||
|
||||
---
|
||||
|
||||
## Usage of XOR ##
|
||||
|
||||
Bitwise operator, XOR, is the bare bone of symmetric key encryption algorithms. Like in the block cipher algorithm above the circle with a cross inside represents the XOR symbol. When reversing assembly code to identify the usage of cryptographic algorithms, you typically want to look for XOR instruction with 2 different registers.
|
||||
|
||||
**Note:** Do not mistake instructions such as xor eax, eax for usage of crypto, because they are usually used for clearing out a register (e.g., eax in this case).
|
||||
|
||||
In function `sub_45B5AC`, `xor [esi], al`, is another nice indicator of encryption usage.
|
||||
|
||||
---
|
||||
|
||||
## Suspicious Instructions ##
|
||||
|
||||
In the beginning of this section, it mentioned you need to be suspicious of NOP instructions; however, they are not indicators for usage of cryptographic algorithms. They usually show that the malware author did not want the function to be analyzed or detected. Inserting NOPs changes the patterns of the bytecode of a binary, and makes it harder for AV’s signatures to detect those patterns. As an analyst, when I see these NOPs, I can usually tell that I am in the right spot (or a spot that the malware author does not want me to be), so I start digging deeper.
|
||||
|
||||
The next subsection will go over identifying which cryptographic algorithm this malware is using.
|
||||
|
||||
[Section 3.2 <- Back](https://securedorg.github.io/RE102/section3.2) | [Next -> Section 4.1](https://securedorg.github.io/RE102/section4.1)
|
||||
123
RE102/re102_section5.1.md
Normal file
@@ -0,0 +1,123 @@
|
||||
---
|
||||
layout: default
|
||||
permalink: /RE102/section5.1/
|
||||
title: Setup
|
||||
---
|
||||
[Go Back to Reverse Engineering Malware 102](https://securedorg.github.io/RE102/)
|
||||
|
||||
# Section 5.1: Debugging #
|
||||
|
||||
Debugging should be your last resort because it can be time consuming. The purpose of doing static analysis is to know where you are. Be sure to take a VM snapshot before you begin debugging. This snapshot will come in handy when you accidently run the malware sample. Frequent snapshots save your debugging work so you won’t lose your place.
|
||||
|
||||
## Create the Breakpoints ##
|
||||
|
||||
Open decrypted_shellcode.exe in x32dbg.
|
||||
|
||||
At this point you should have recorded the following functions and locations:
|
||||
1. `sub_402B1C` @ `00401D9B` - The function the loads the libraries
|
||||
2. `sub_4014AA` @ `0040560B` - The function that checks for sample, sandbox, and virus
|
||||
3. `jz loc_405272` @ `004019E4` - The jump to modify the EFlags if necessary
|
||||
4. `jnz loc_405277` @ `0040526C` - The jump to modify the EFlags if necessary
|
||||
5. `loc_405272` @ `00405272` - The location that calls the unknown API
|
||||
6. `loc_405277` @ `00405277` - The location that calls the unknown API
|
||||
|
||||
Place a breakpoint with x32dbg using the command line. Example: `bp 00401D9B`
|
||||
|
||||

|
||||
|
||||
Now press **F9** to run the program to breakpoints until you reach `004019E4`.
|
||||
|
||||

|
||||
|
||||
Scroll down to check out offset `00405272`. Looks like the [esp+1C] is using Path Windows APIs to check the strings against sample, sandbox, and virus. Since your exe name is and path does not contain these words, it will not jump. So you won’t need to force the jump. Keep pressing F8 (step over) until you reach offset `00405277`.
|
||||
|
||||

|
||||
|
||||
Congrats! This was the first evasion technique you worked through. Now that you know what these API calls are, you should be filling in your IDA comments with these APIs.
|
||||
|
||||
---
|
||||
|
||||
## Adding Resources ##
|
||||
|
||||
Step **F7** the program until you reach the next function `sub_40487D`. Be sure to record the arguments pushed onto the stack. Step Into **F7** function `sub_40487D`. Next step until you reach `00401632` and look down to `00401645`. The calls to GetModuleHandle and FindResource means it’s about to access a resource in the exe.
|
||||
|
||||
This is typically how you get a resource from an exe:
|
||||
|
||||
```
|
||||
HMODULE hModule = GetModuleHandle(NULL); // get the handle to self (exe)
|
||||
HRSRC hResource = FindResource(hModule, MAKEINTRESOURCE(RESOURCE_ID), RESOURCE_TYPE);
|
||||
HGLOBAL hMemory = LoadResource(hModule, hResource);
|
||||
DWORD dwSize = SizeofResource(hModule, hResource);
|
||||
LPVOID lpAddress = LockResource(hMemory);
|
||||
```
|
||||
|
||||
When you turned the shellcode into an exe it did not include any resources. Remember that the original exe is where this shellcode gets executed. So you will need to get the resource from the original exe and import them into shellcode exe. The argument passed to the function `sub_40487D` was 0xE38 which is 1000 in decimal. If you keep stepping through function `sub_40487D` you will see the routine above and notice that the argument to find the resource is 1000.
|
||||
|
||||
```
|
||||
HRSRC WINAPI FindResource(
|
||||
_In_opt_ HMODULE hModule,
|
||||
_In_ LPCTSTR lpName, //ID of the resource
|
||||
_In_ LPCTSTR lpType
|
||||
);
|
||||
```
|
||||
|
||||

|
||||
|
||||
Close x32dbg while you edit the decrypted_shellcode.exe.
|
||||
|
||||
Open up the original exe in CFF explorer and look for the resource 1000. Next export this resource under Resource Editor, right-click and Save Resource (RAW). Take a moment and look at the data of this resource. Hint: looks like more junk data.
|
||||
|
||||

|
||||
|
||||
Once you exported the resource 1000, open the decrypted_shellcode.exe with CFF explorer. In the Resource Editor add Add Custom Resource (Raw) with the id of 1000. It should mirror the original exe. Afterwards open decrypted_shellcode.exe with x32dbg again. Navigate back to function `sub_40487D` or just set a breakpoint at `0040487D` and run until that function.
|
||||
|
||||
---
|
||||
|
||||
## Saving Junk and Chunks in Memory ##
|
||||
|
||||
Keep stepping until you reach `0040416F` where you will see that the resource is being placed into a new memory allocation. Remember that VirtualAlloc is typically followed by a Move function. After the VirtualAlloc function is returned make sure you note the address of the newly allocated memory. This function will return that memory address value in the `eax` register.
|
||||
|
||||

|
||||
|
||||
Once you are done stepping through function `sub_40487D` step until you reach `loc_4014C2`.
|
||||
|
||||

|
||||
|
||||
The size 0x318 is a common theme for the next couple of function calls. This is where you will see another routine of VirtualAlloc and Move. It will store the first 0x318 bytes into the newly allocated memory.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Does function `sub_403BC2` look familiar? Here is the breakdown:
|
||||
|
||||
```
|
||||
Arg_0 CopiedData+offset 20h
|
||||
Arg_1 0x2F8 size
|
||||
Arg_2 CopiedData
|
||||
Arg_3 0x20 size
|
||||
```
|
||||
|
||||
Why offset 0x20? Here is the dump of the CopiedData:
|
||||
|
||||

|
||||
|
||||
At this point it’s too early to guess what this data does.
|
||||
|
||||
```
|
||||
78 95 4D 26 0A C4 55 94 74 AF 5A 78 33 71 58 EB CD 05 B3 D6 5A B7 D6 05 43 D8 1A 7D 4A B6 EA 10
|
||||
```
|
||||
|
||||
In IDA, glance through function `sub_403BC2`. There are 3 hints that give away what this function is doing.
|
||||
|
||||
* The use of 0x100 and 0x20
|
||||
* Multiple loops
|
||||
* The use of XOR
|
||||
|
||||
If you remember from the previous Section 4, multiple loops and the use XOR is indicative of being some kind of crypto algorithm. There is a theme of crypto here but there just a slight difference. The use of anding a value with `800000FFh` is also a form of modulo for `X mod 256`. Earlier you saw that the modified RC4 algorithm was using a delphi mod function instead.
|
||||
|
||||
Looks like the is using RC4 again, but you might want to step through the algorithm to confirm if it’s true RC4 or modified RC4 like from Section 4. Once you have you will notice that the first 32 bytes (0x20) decrypted the rest of the CopiedData 760 bytes (0x2F8). Be sure to save the address of this memory in your notes and renaming functions in IDA because you will need it for Section 6.
|
||||
|
||||
Step through until you reach `loc_401CCA` and continue to the next page.
|
||||
|
||||
[Section 5 <- Back](https://securedorg.github.io/RE102/section5) | [Next -> Section 5.2](https://securedorg.github.io/RE102/section5.2)
|
||||
161
RE102/re102_section5.2.md
Normal file
@@ -0,0 +1,161 @@
|
||||
---
|
||||
layout: default
|
||||
permalink: /RE102/section5.2/
|
||||
title: Setup
|
||||
---
|
||||
[Go Back to Reverse Engineering Malware 102](https://securedorg.github.io/RE102/)
|
||||
|
||||
# Section 5.2: Evasion Techniques #
|
||||
|
||||
## Anti-Automation ##
|
||||
|
||||
Before you continue to `loc_401CCA`, there were some Anti-Automation behaviors that were not discussed from Section 3.1. There calls to GetForegroundWindow, Sleep, then GetForegroundWindow is an anti-automation technique to ensure that there is an actual user changing the state of the foreground window. Typically in automated sandbox testing there is no user interaction unless they accounted to build that into their VM.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Anti-Debugging ##
|
||||
|
||||
If you remember from Section 3.1 and 3.2, there were many calls to OutputDebugString. Instead of directly calling for IsDebuggerPresent, calling to OutputDebugString and checking the success or failure is another technique to check if there is a debugger running. It’s a simple tactic to avoid reverse engineering.
|
||||
|
||||
---
|
||||
|
||||
## VM Evasion ##
|
||||
|
||||
There are many resources for a developer to identify if the process is running in a Virtual Machine. Paranoid Fish or pafish is one of the more well-known automated VM identification scripts available. You can view the code here: [https://github.com/a0rtega/pafish](https://github.com/a0rtega/pafish).
|
||||
|
||||
Every VM distro has their own filesystem and registry indicators. Products such as VMware and Vbox often have software installed to help with host to guest sharing. Hardware simulation will contain strings and naming related to the VM product. Some malware will check if it is running inside a VM and change its behavior.
|
||||
|
||||
In IDA, start back at `loc_401CCA` where you will be able to identify some VM Evasion techniques.
|
||||
|
||||
---
|
||||
|
||||
### Checking Hardware Device ###
|
||||
|
||||
Earlier in this section, there was an anti-analysis technique of pushing strings to the stack. In function `sub_4029E7` until you are in function `sub_402274`, you can see it’s pushing **H** and **A** in the the screenshot below.
|
||||
|
||||

|
||||
|
||||
Go ahead and go through all the strings that are being pushed to the stack. It should com out to:
|
||||
|
||||
```
|
||||
HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\ Logical Unit Id 0\Identifier
|
||||
```
|
||||
|
||||
At the very end of the function it jumps to `loc_404777` where it calls `sub_403F73`. This is where the shellcode pushes strings **vmware, qemu,** and **vbox**. In the debugger, set a breakpoint and run/step to 00406AB6 within function `sub_4037FD`. This is where the call to RegKeyOpenEx happens.
|
||||
|
||||

|
||||
|
||||
If you follow the stack argument DWORD in the dump you can see the full strings. To view this, right click on the stack argument and select **Follow DWORD in dump**.
|
||||
|
||||

|
||||
|
||||
Open regedit.exe in Windows and verify that this registry key exists under HKEY_LOCAL_MACHINE. If this key exists RegKeyOpenEx will return 0, if not 2. In the debugger, Step over **F8** this function call. Fortunately this VM was built with an IDE instead of scsi hardware. You can verify this by looking at Virtualbox’s storage settings.
|
||||
|
||||

|
||||
|
||||
If the VM you are working in does happen to have this registry key, you can always bypass the check. Put a breakpoint at 00404977 so that you won’t miss this next jump. When you are debugging you can modify the **ZF flag** so that `jz loc_404D01` will fail and continue onto the next check.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### Check the System Bios ###
|
||||
|
||||
Continue to step **F7** to function `sub_4021FE` at `00404982`. This function is using the same anti-analysis technique by pushing strings onto the stack. The strings **vbox** and **qemu** are used to check the value in another registry key. Step through the rest of this function to reveal the full string until you reach `004047A7`.
|
||||
|
||||

|
||||
|
||||
The registry key that you should have recovered from the stack is:
|
||||
|
||||
```
|
||||
HARDWARE\Description\System\SystemBiosVersion\SystemBiosVersion
|
||||
```
|
||||
|
||||
Verify in the registry using regedit.exe that this registry key exists. It looks like **vbox** does exist in the SystemBiosVersion string. You will need to modify the jumps in order to bypass this check in order to continue.
|
||||
|
||||

|
||||
|
||||
There are 2 places where you can choose to modify the jump:
|
||||
|
||||
* Right after the registry key check function:
|
||||
|
||||

|
||||
|
||||
* or Right after `sub_4021FE`:
|
||||
|
||||

|
||||
|
||||
If you modified either of the jump calls above while debugging you should have reached `loc_4010FE` and `sub_4029F1`. Below how you modify the second jump.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### Check for VM drivers ###
|
||||
|
||||
Just like the previous functions, the strings a pushed to the stack. Look for the instruction `call dword ptr [ebx+0B0h]` which is where you set a breakpoint at `00405248`. In the debugger, this will call GetSystemDirectory which will return %system32%. Keep stepping through this function to get the full paths of the files it is checking for.
|
||||
|
||||
* %system32%\drivers\vmmouse.sys
|
||||
* %system32%\drivers\vmhgfs.sys
|
||||
* %system32%\drivers\VBoxMouse.sys
|
||||
* %system32%\drivers\VBoxGuest.sys
|
||||
|
||||
Keep stepping through function `sub_4029F1` until you get back to `0040110B` where `jnz sub_401117` and force the jump to `sub_401117`.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### Check for VM DLLs ###
|
||||
|
||||
Keep stepping into `sub_401117` until you reach some interesting immediate values. Go ahead and convert the immediate values at `00405884` into strings.
|
||||
|
||||

|
||||
|
||||
This function is checking for sbiedll.dll which is a DLL used by the Sandboxie sandbox. If you are working with Vbox, this DLL will not exist so you won’t need to bypass a jump. Keep working your way through this function because it’s not done with all the checks.
|
||||
|
||||
---
|
||||
|
||||
### Check the Physical Drive ###
|
||||
|
||||
In IDA, look into `sub_406FCC` at `0040218D` after the sandboxie DLL check. Based on the logic below you might not need to step into this function. You can always force the jump to `loc_402192` and skip over `sub_406FCC`. For the purposes of recognizing VM evasion, you should step through this function.
|
||||
|
||||

|
||||
|
||||
Put a breakpoint at `00404403` where the instruction `call dword ptr ds:[esi+98]` because this is the next API call. It tries to call CreateFile the PhysicalDrive0 in order to read it.
|
||||
|
||||

|
||||
|
||||
Because the above check failed, it will perform another device check. Keep stepping through the program until you reach 00406266 where the second API call is `call dword ptr ds:[esi+94]`. It is calling DeviceIoControl where it will check the \\.\PhysicalDrive0 for the following strings:
|
||||
|
||||
* qm00001
|
||||
* virtual
|
||||
* array
|
||||
* vbox
|
||||
* vmware
|
||||
* 00000000000000000001
|
||||
|
||||
Here is the API function as reference:
|
||||
|
||||
```
|
||||
BOOL WINAPI DeviceIoControl(
|
||||
_In_ HANDLE hDevice,
|
||||
_In_ DWORD dwIoControlCode,
|
||||
_In_opt_ LPVOID lpInBuffer,
|
||||
_In_ DWORD nInBufferSize,
|
||||
_Out_opt_ LPVOID lpOutBuffer,
|
||||
_In_ DWORD nOutBufferSize,
|
||||
_Out_opt_ LPDWORD lpBytesReturned,
|
||||
_Inout_opt_ LPOVERLAPPED lpOverlapped
|
||||
);
|
||||
```
|
||||
|
||||
After DeviceIOControl is called do not take the jump after at `00405778` or `loc_405778`. This will cause the device to close and return back to the main function where the sandboxie DLL was checked.
|
||||
|
||||

|
||||
|
||||
This jump should land you at `loc_402192` or `00402192`. **Congratulations!** You have made it past several VM evasion techniques. The next Section 6 will go over identifying a packer.
|
||||
|
||||
[Section 5.1 <- Back](https://securedorg.github.io/RE102/sectio5.1) | [Next -> Section 6](https://securedorg.github.io/RE102/section6)
|
||||
102
RE102/re102_section5.md
Normal file
@@ -0,0 +1,102 @@
|
||||
---
|
||||
layout: default
|
||||
permalink: /RE102/section5/
|
||||
title: Setup
|
||||
---
|
||||
[Go Back to Reverse Engineering Malware 102](https://securedorg.github.io/RE102/)
|
||||
|
||||
# Section 5: Evasion Techniques #
|
||||
|
||||

|
||||
|
||||
This section will focus on identifying various Evasion Techniques as well as working around them during the debugging phase. Now that you will be working with an new executable, you will need to create another road map.
|
||||
|
||||
## Control Flow Obfuscation ##
|
||||
|
||||
You will notice that the shellcode is broken up into extraneous and unnecessary jumps. This is meant to throw off malware analysis with these anti-disassembly techniques. Malware that has this kind of useless instructions is usually processed with some kind of obfuscation kit. Malware authors rarely write new shellcode and will sell, share, or reuse this code.
|
||||
|
||||
Going forward, you should be viewing the disassembly in graph mode. It will be easier to read the control flow. Below is an example of the Flow-chart mode of the useless jumps.
|
||||
|
||||

|
||||
|
||||
## Where to Start? ##
|
||||
|
||||
There are no strings for us to investigate and there are no functions parsed by IDA. Tip: The professional version of IDA does a great job at parsing functions. So you need to start exploring each function one by one finding interesting code to look at. If this is too daunting, then manual debugging is your next option. The goal is to make a road map of shellcode by working backwards.
|
||||
|
||||
## String Obfuscation ##
|
||||
|
||||
The first function call sub_404C1E doesn’t look like something interesting, so move on to the next function call to `sub_402B1C`. This function is a jump-wrapper for the function `sub_4059A3`.
|
||||
|
||||
Notice anything strange about the immediate values being placed onto the stack? These are actually strings. By breaking up the string and pushing it onto the stack is a common way to hide strings from malware analysts. Go ahead right-click these numbers and convert it to a string (R).
|
||||
|
||||

|
||||
|
||||
They should look like this afterwards:
|
||||
|
||||

|
||||
|
||||
## Dynamic Library Loading ##
|
||||
|
||||
With shellcode or position independent code (PIC), the code needs to load resources and libraries to work with before it performs the nefarious routines. Based on the strings above you can tell that it is going to load these libraries:
|
||||
|
||||
* user32
|
||||
* shell32
|
||||
* shlwapi
|
||||
* advapi32
|
||||
|
||||
## Access to the Process Environment Block (PEB) ##
|
||||
|
||||
After the advapi32 string gets loaded onto the stack, enter the function `sub_405421`.
|
||||
This function is accessing the FS segment register `fs:[0x30]` which is the pointing to the Process Environment Block. This is a common shellcode tactic to get handles to loaded windows libraries a.k.a. Modules, specifically the base of kernel32 from the PEB.
|
||||
|
||||
```
|
||||
mov eax, 30h
|
||||
mov eax, fs:[eax] ; Get the address of PEB
|
||||
mov eax, [eax+0Ch] ; Get the address of PEB_LDR_DATA
|
||||
mov eax, [eax+0Ch] ; InLoadOrderModuleList
|
||||
mov eax, [eax] ; get the next entry
|
||||
mov eax, [eax+18h] ; get Kernel32
|
||||
```
|
||||
|
||||

|
||||
|
||||
The second instruction `mov eax, [eax+0Ch]` gets the address of the PEB Loader Data from the [PEB](https://msdn.microsoft.com/en-us/library/windows/desktop/aa813706%28v=vs.85%29.aspx) struct. The [PEB_LDR_DATA](https://msdn.microsoft.com/en-us/library/windows/desktop/aa813708(v=vs.85).aspx) contains the struct for the InMemoryOrderModuleList which is where it gets the pointer for Kernel32. Note: there are many great Shellcode resources available that explain this technique. I just want you to recognize the instruction `fs:[0x30]`.
|
||||
|
||||
```
|
||||
struct PEB_LDR_DATA {
|
||||
DWORD Length; ; 0
|
||||
BYTE Initialized; ; 4
|
||||
void* SsHandle; ; 8
|
||||
struct LIST_ENTRY InLoadOrderModuleList; ; 0ch
|
||||
struct LIST_ENTRY InMemoryOrderModuleList; ; 14h
|
||||
struct LIST_ENTRY InInitializationOrderModuleList; ; 1ch
|
||||
};
|
||||
```
|
||||
|
||||
Save these functions `sub_402B1C` and `sub_405421` for debugging later. Also include these into your road map for the shellcode executable.
|
||||
|
||||
## Checking the Filename and Path ##
|
||||
|
||||
Go to the next function `sub_4014AA` which is a wrapper for function `sub_401D36`. Again, this function is using an anti-analysis technique of pushing a string one by one onto the stack. Can you guess what this function is doing?
|
||||
|
||||

|
||||
|
||||
The strings are:
|
||||
|
||||
* sample
|
||||
* sandbox
|
||||
* virus
|
||||
|
||||
It seems the malware author wanted to detect if this executable contained strings related to malware analysis. You will need to debug this function to see which string it’s comparing these values. You will want to avoid this function because you need to get around the anti-analysis detection. Remember that functions return 0 or 1 in `eax` depending on the success or failure. You want this function to fail or return 1 because you want to get around these traps. Below the instruction `cmp eax, 1` and `jz loc_405272` is where the comparison to the return value occurs. During debugging, you would want to force the jump by changing the EFlags.
|
||||
|
||||

|
||||
|
||||
## Time to Start Debugging ##
|
||||
|
||||
After `jz loc_405272` there is a call to [esp+1Ch] this is actually calling a Windows API call that was loaded there by the loaded library function `sub_402B1C`. It would be tedious to go through those locations by hand, so let’s start debugging.
|
||||
|
||||

|
||||
|
||||
The next page will go over debugging the decrypted_shellcode.exe with x32dbg.
|
||||
|
||||
[Section 4.3 <- Back](https://securedorg.github.io/RE102/section4.3) | [Next -> Section 5.1](https://securedorg.github.io/RE102/section5.1)
|
||||