Skip to content

Commit

Permalink
content-update
Browse files Browse the repository at this point in the history
  • Loading branch information
BitwiseOperator committed Jun 8, 2024
1 parent 32c0498 commit e7313c4
Showing 1 changed file with 21 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2131,39 +2131,39 @@

Locate the executable sample in [simpleAntiAnalysis Lab](https://github.com/HuskyHacks/PMAT-labs/tree/main/labs/2-5.AntiAnalysis/1.simpleAntiAnalysis) and copy it to the FLARE-VM Desktop. For the purpose of this lab, we will skip right to the Advanced Static Analysis portion. Open the simpleAntiAnalysis-cpp.exe binary in Cutter to begin analysis.

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-3.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-3.png)

This sample is a 64-bit binary written in C++ and weighs in at a whopping 313KB. String analysis indicates that this sample has been cross-compiled from Linux using the Minimum GNU Compiler for Windows (mingw).

In Cutter, locate the WinMain method within the binary and double click to load into that method:

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-4.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-4.png)

Then, switch to the Graph View:

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-5.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-5.png)

The sample performs its main work here in this method. The first interesting thing here is the presence of the ```IsDebuggerPresent()``` API call. Let’s examine the Microsoft documentation for this API call:

[IsDebuggerPresent function (debugapi.h) - Win32 apps](https://learn.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-isdebuggerpresent)

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-6.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-6.png)

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-7.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-7.png)

The API call is quite straightforward. This returns a Win BOOL value depending on if the program detects an attached debugger.

The core of the logic of the debugger check exists in these instructions:

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-8.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-8.png)

First, the `IsDebuggerPresent()` API call occurs. The specifics of how a debugger is detected is not particularly interesting for our purposes. What is interesting, however, is the return value that is loaded into `EAX` after this call returns. Like the documentation says, the program sets the value of EAX to 1 if a debugger is detected and sets the value of EAX to 0 if a debugger is not detected.

Then, the program performs a bitwise `AND` of the value of `EAX`. We’ve seen this before in the Binary Patching section (https://notes.huskyhacks.dev/notes/on-patching-binaries). The bitwise `AND` of `EAX` will set the Zero Flag (ZF) to 1 or 0. This effectively means the Zero Flag is set depending on if a debugger is detected or not.

Note: though this binary is 64-bit, EAX is used here to perform the `TEST` instruction. This is because in 64-bit architecture, the smaller registers can still be used if the values are small enough to fit in them. That’s why you see values moving in and out of AL, EAX, and the like.

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-9.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-9.png)


Then the program performs a `SETNE` `AL` (SET If Not Equal To) instruction call. We have not seen this instruction before, but it is quite simple:
Expand All @@ -2184,17 +2184,17 @@

In the previous section on Binary Patching , we saw the `JNE`(Jump If Not Equal To) instruction. `JNE` controlled the flow of the program based on if the Zero Flag was set to 1 or 0. In this program, we have a similar instruction, which is `JE [Memory Location]` (Jump if Equal To). JE evaluates the Zero Flag and acts as the inverse instruction: if the Zero Flag is equal to 1, the jump is taken. If the Zero Flag is equal to 0, the jump is not taken.

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-10.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-10.png)

In this case, the Jump here directs the program to the proper detonation of the malware, where a simple message box pops up and says that the coast is clear!

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-11.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-11.png)

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-12.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-12.png)

However, the opposite code path pops up a message box that identifies that a debugger is present. We can load this program into x64dbg and run the program (F9) until we see the message box:

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-13.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-13.png)

**Ok, So What Does This Actually Do?**

Expand Down Expand Up @@ -2250,51 +2250,51 @@

First, let’s execute the program in a debugger and see how it functions. Exit out of Cutter and load the program into x64dbg. Run the program (F9) until the message box triggers:

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-14.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-14.png)

Let’s find the instruction that performs the `IsDebuggerPresent()` check. It should be close to the start of the WinMain function, which we saw in Cutter.

Restart the program (Ctl+F2) and return to the entry point of the program. Right Click inside the CPU section and select “Search For → All Modules → String References”

In the String search panel, enter: `IsDebuggerPresent`

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-15.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-15.png)

The string “IsDebuggerPresent” is passed to the `LoadLibrary` and `GetProcAddress` functions so it can be resolved and used when the program runs. This is useful to us to get us in the vicinity of where the debugger check is performed in the program. Set a breakpoint on this string reference (F2).

Return to the CPU panel and continue the execution of the program by pressing F9. We eventually hit out breakpoint:

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-16.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-16.png)

The string reference for “IsDebuggerPresent” is currently being resolved, so we’re close to where we want to be. Continue to step through the program with F8 until you return from this call:

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-17.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-17.png)

After returning from this call, we are here in the program (I recommend setting a breakpoint here!):

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-18.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-18.png)

This should look familiar! `TEST EAX,EAX`, then `SETNE AL`, then `TEST AL,AL`, then `JE` to a location in the program. In fact, this is exactly what we saw earlier in Cutter:

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-19.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-19.png)

To perform the patch, we need to change the flow of the program. Just like with static patching in the previous section, there are a few ways to do this.

Notice how when RIP is on the jump instruction, the Zero Flag is cleared (set to 0). This means that a debugger has been detected and this jump will go to the message box that says “I see your debugger over there!”

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-20.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-20.png)

The running process memory is ours to modify to our liking. Hey, if the malware is running on our computer and we’re the administrator, who says we can’t modify the runtime values in memory? No one says that, so we will do just that! Why don’t we change the Zero Flag to a 1? That way, we will jump to the other code path!

Double click on the Zero Flag to flip it to a 1:

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-21.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-21.png)

Now, the program proceeds to the code path that spawns two message boxes that indicate the coast is clear to run the payload. Continue execution with F8 to see the parameters for each message box get loaded into the registers and then the CALL EAX instructions which spawn the message boxes:

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-22.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-22.png)

![alt text](/knowledge_base/images/HTA-img-0s9ujsj-23.png)
![alt text](/Knowledge_Base/images/HTA-img-0s9ujsj-23.png)

Even with an attached debugger, we have detonation! We have successfully identified and defeated an anti-analysis technique!

Expand Down

0 comments on commit e7313c4

Please sign in to comment.