# NTU Malware Reverse Lab 3 write up ###### tags: `NTU_MR` `Malware Reverse Engineering and Analysis` `NTU` [TOC] | Name| 何秉學 |StuID| R11921A16| | -------- | -------- | -------- | -------- | ## Review Packing and Unpacking * How does packing and unpacking work? 作者會把原本的code section和data section,放在UPX1,並且用unpacking stub(裡面存放解殼的程式),把UPX1的內容一點一點的還原回UPX0(也就是空區段),並跳回正常程式的執行進入點(original entry point, `OEP`),最後跳回去的動作叫做`Tail Jump`或`Long Jump`,另外,多長的jump才是長,可能要依照經驗值判斷,或是直接跳過去後分析程式在幹嘛 ![](https://imgur.com/TdhA1Tz.png) * 實際上執行脫殼的時候,除了`OEP`的重建外,還需要重建`Imports`,這兩者都處理好後才算是脫殼完成 * 當分析脫殼執行到如下圖這樣的情況時,就離終點不遠了,也就是`jmp`的地址離目前的程式很遠,且之後的程式有很多空指令或垃圾`byte`,<font color="FF0000">**此為`UXP`殼的特徵**</font> ![](https://imgur.com/KUbYRWa.png) * 可以用`PEiD`這個工具(或是用`Entropy`之類的,但是不一定準確)判斷樣本有沒有加殼,或是加了甚麼殼,上圖是沒有加殼的一般程式,下圖是加了`UPX`的加殼程式 ![](https://imgur.com/T0sFBc6.png) ![](https://imgur.com/9hDQtVr.png) * 若是要處理`Import Table Reconstruction`,可以用`OllyDump`、`ImpRec`或是`Scylla`這些工具來進行,在`Practice`中是用`Scylla`演示(且可以搭配`x32dbg`或`x64dbg`進行) * 老師有說在`Long Jump`之前會搭配`pop` instruction,這可能可以當作解析`OEP`的線索 * `Tail Jump`,不一定是用`jmp`,也可以是`call` instruction;另外,跳轉的地址也不一定是一個明確的地址,也可能用暫存器存起來,這部分可以注意一下 ## Practice - `upx_exercise.exe` ### Observation * First things first, we can observe the file by executing it directly. Obviously, you should enter correct `CTF` key by analyzing. ![](https://imgur.com/RcXtqnV.png) ### Unpacking #### Static analysis - `IDA Pro` * You are not allowed to disassembly by doing nothing, because it was packed by `UPX`. Therefore, our objective is to unpack it and try to analyze it original code to get the `CTF Flag`. ![](https://imgur.com/CkqgK9U.png) #### Dynamic analysis - `x32dbg` * In `UPX-based` packing, it has a feature that in order to not let the data be flushed during unpacking, it must store all data to the stack by using <font color="FF0000">`pushad`</font> instruction. ![](https://imgur.com/lgZWxPL.png) * Then, you'll see a lot of `jmp` instruction to unpack the original code. ![](https://imgur.com/W0Bj1dq.png) * Scrolling down the code, you'll see a <font color="FF0000">`popad`</font> instruction at `0x0134AEDE` , a <font color="FF0000">`jmp`</font> instruction at `0x010EAEEC`, and a lots of `null` instruction which all three are satisfied all features that `UPX-based` packing method has. It'll restore all data that stored in stack and jump to `upx_exercise.134244D`. ![](https://imgur.com/vRJFQdU.png) * Set the break-point and press `run` button in `x32dbg`, then press `step into` button to observe the code. * Now, the code has already unpacked, then we can use <font color="FF0000">**`Scylla`**</font> to do `Import Reconstruction`. ![](https://imgur.com/Tjn207G.png) ![](https://imgur.com/YBbISuc.png) * Press `IAT Autosearch`(Import Address Table) button to search and then press `Get Imports` button. Finally, you will get all imports that this file used, and `Scylla` will help you to rebuild it. ![](https://imgur.com/yUzV49b.png) Press `Dump` button to get `IAT` file. ![](https://imgur.com/6RkqgO4.png) * Press `Fix Dump` and choose the file what we dump to reconnect the `IAT` and this file. You'll see the log said `Import Rebuild success` and you'll get a new file named `upx_exercise_dump_SCY.exe` that repaired by `Scylla`. ![](https://imgur.com/CIJEKcY.png) ### Analyze #### Re-static analysis - `IDA Pro` * Used `IDA` to reanalyze the unpacking file. * Used string searching to find the string `nope` that appear in your `cmd`. ![](https://imgur.com/OeInenc.png) * Used cross reference to find which part has used it. ![](https://imgur.com/o7xwDFE.png) ![](https://imgur.com/zvQqq0u.png) * The main part is shown as below ```cpp ... sub_E01EB0(std::cin, &Memory); LOBYTE(v116) = 1; MEMORY[0] = 0; v96 = 0xFCC1D3C4; v97 = 0xD8D2C8DE; v98 = 0xD8D3E8E0; v99 = 0xD8C2EFB0; v100 = 0xC2ECB3C1; v101 = 0xB3EBE1D8; v102 = 0xD5F3D8BE; v103 = 0xB3EFD8DE; v104 = 0xF5C2E3D5; v105 = 0xFAD6D6D8; v64 = 1; HIBYTE(v95) = 1; v65 = 0; v93 = 0; while ( v65 < 40 ) { v66 = (char *)&Memory; if ( v111 >= 16 ) v66 = (char *)Memory; v67 = v66[v65] ^ 0x87; v68 = *((unsigned __int8 *)&v96 + v65); v94 = 0; if ( v67 != v68 ) v64 = v94; HIBYTE(v95) = v64; v93 = ++v65; } v69 = "Congratz?!"; if ( !v64 ) v69 = "Nope!"; ... ``` * From `v96` to `v105`, it stored 40 bytes and it seems do something in while loop 40 times. In addition, `v67 = v66[v65] ^ 0x87;` this line used `xor` instruction that seems a encrypt part. And then it compared `&v96 + v65` and `v67` that encrypt the string what you input. * If all the strings you input after process `xor` to `0x87` are strictly the same with `v96` to `v105`, then it'll print `Congratz?!`, otherwise, print `Nope`. * Used [online_xor](https://xor.pw/#) to get `v96` to `v105` encrypted strings. ![](https://imgur.com/5CkTwXn.png) And then used [online_hex2ascii]() to get the `CTF Flag`. ![](https://imgur.com/BHA0PDT.png) * The answer is <font color="FF0000">`**CTF{YOU_goT_7hE_F4kE_fl49_tRY_h4RdEr_QQ}**`</font>, though it is not a real answer. * Note that, the demo from TA is finished, therefore, I still don't know the real flag is. ## Homework - `upx_Revil.exe` ### Static Analysis Observation * Use `IDA` to analyze this sample and obviously packed sample ![](https://imgur.com/uzVMd5r.png) * Use the skill above then you can answer the question easily. ## Homework - `custom_packer_Revil.exe` ### Static Analysis Observation - `DetectItEasy` * Though I used the tool, `DetectItEasy` to check if this sample was packed or not, the answer is not quite explicit. ![](https://imgur.com/Efv46o8.png) * Through the write up made by [Security Joe](https://github.com/securityjoes/conferences/tree/main/Confidence%202022/watch_out_and_just_skip_the_packer), it's not a simple `UPX` sample. > This packer can be classified as a <font color="FF0000">hybrid packer</font> because during its execution it injects several pieces of `shellcode` to finally replace the complete memory image of the PE. A diagram that explains this kind of packer is shown below. ```! This kind of packer will do a self injection in its own memory space.Basically, it'll allocate or creating a new memory section in the same process and it can write shellcode or complete PE files to execute. ``` * Basically, it's going to read the encrypted content, and gonna save or gonna copy that to the new section(the <font color="FFAA00">yellow</font> block) ![](https://user-images.githubusercontent.com/8562692/172320227-0bb75da9-2ec3-4276-ba5d-5544668b50f0.png) ### Analyze & Find `OEP` 1. Finding first injected `shellcode` (`LocalAlloc`) * Set the break point at `0x00404DB6` and step into this line ![](https://imgur.com/z6JFF9C.png) * And you'll find the module that you are analyzing is `kernel32.dll`. ![](https://imgur.com/anxCj4G.png) * This is not what we care, so we press the button(`Execute till return`) to skip this module. ![](https://imgur.com/awQDSUW.png) And then step into this operation to go back to the custom packer REvil from windows library. * Follow the memory address in dump ![](https://imgur.com/eatiw0X.png) Then continue to execute the code, you will see there are 3 nested loop. Please pay attention to the dump. When I finish the loop, the dump memory is different(Fig.2). ![](https://imgur.com/pARISgf.png) ![](https://imgur.com/oCy70c4.png) These loops are aim to moving the `shellcode` to memory section, just as the same what we talked about before. * While you are continuing to execute forward, you can see the dump memory has changed at `0x00404E38`. ![](https://imgur.com/LVKPdMZ.png) \* Note that you can dump these memory to a new file by right click and select `Follow in Memory Map`, and then right click again then choose <font color="FF0000">`Dump memory to File`</font> \* Note that the file you dump is actually a `shellcode`. How to know? 2. Finding second injected `shellcode` (`VirtualAlloc`) * Find the expression by pressing `Ctrl+G` and type `VirtualAlloc`. ![](https://imgur.com/UBEXcBO.png) Set the break point at the first line and do the same thing above. Pressing `Execute till return` and check the memory by right click `EAX` and choose `Follow in Dump`. ![](https://imgur.com/QjXxqKH.png) Finally, press `step into` to return * Like the same outcome above. While you are continuing to execute, you'll notice that memory have changed when you step over `0x02B95269`. ![](https://imgur.com/YRUQQo4.png) \* Note that this is 2nd `shellcode` that can check in disassembler. ![](https://imgur.com/4xGJ9Xv.png) * And obviously, `0x02B9527D` is the 2nd tail jump that will jump to <font color="00BFFF">blue</font> `shellcode` block from <font color="FFCC00">yellow</font> `shellcode` block. ![](https://imgur.com/S6RsiQr.png) * You can see that the jumping address is quite different with current address(the following image is not my actually circumstances) ![](https://imgur.com/qqNNPJU.png) 3. Payload decryption (`VirtualAlloc`) * In this section, it'll use `VirtualAlloc` again. So, we just press `Run` button to get in there. And follow the instruction above. ![](https://imgur.com/yrbpTEs.png) * Go back → Follow `EAX` address in dump → Step into → You'll see 3 nested loop again → Set break point → Run → The memory changed in dump again(<font color="FF0000">this is our payload in memory</font>) ![](https://imgur.com/GRTJw51.png) * Dump these code in a new file like above. ![](https://imgur.com/efIF2Xy.png) 4. Code substitution (`VirtualProtect`) * In this section, it'll use `VirtualProtect` `API`, so that we just follow the instruction above. * Find `VirtualProtect` by `Ctrl+G` → Set break point and press `Run` button **Interesting things** Check out [the page](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect) talking about `VirtualProtect`. > Changes the protection on a region of committed pages in the virtual address space of the calling process. To change the access protection of any process, use the VirtualProtectEx function. And you can especiallly take a look at > [in] flNewProtect The memory protection option. This parameter can be one of the memory protection constants. Follow [the page](https://learn.microsoft.com/en-us/windows/win32/Memory/memory-protection-constants), you can notice that 0x40 is <font color="FF0000">**`PAGE_EXECUTE_READWRITE`**</font> You can see the whole parameters about `VirtualProtect` in `stdcall`. ![](https://imgur.com/yCwYFRP.png) **They want to modify the original section(replace)** * Continue the instruction mentioned above: go back → step into 5. Finding the "Tail jump" * Scrolling~~ down and find a looooog jump at `0x001C091E` and step into. ![](https://imgur.com/93t3EUR.png) 6. Finding the `OEP` `0x00404161` is your `OEP` ![](https://imgur.com/eMoPuUe.png) ## Homework 1. Analyze the malware found in the file `workshop_samples.zip` -> `upx_REvil.exe`, generate 'yourself' `writeups` (with screenshots) and answer the follow questions: 1.1 Where is the memory address of the **tail jump**? Ans: When you see the machine instruction `popad`, the tail jump address is <font color="FF0000">`0x00283F8C`</font> ![](https://imgur.com/WhnF265.png) 1.2 Where is the **`OEP`** of the packed sample? Ans: The **`OEP`** address is <font color="FF0000">`0x00264161`</font> 2. Analyze the malware found in the file `workshop_samples.zip` -> `custom_packer_REvil.exe`, generate 'yourself' `writeups` (with screenshots) and answer the follow questions: 2.1 Where is the memory address of the **tail jump**? Ans: Scrolling~~ down and find a looooog jump at `0x001C091E` and step into. ![](https://imgur.com/93t3EUR.png) 2.2 Where is the **`OEP`** of the packed sample? Ans: <font color="FF0000">`0x00404161`</font> is your `OEP` ![](https://imgur.com/eMoPuUe.png)