First, the Reverse debugging technology
Anti-debugging technology is a common kind of counter detection technique, because malware always attempts to monitor its own code to detect if it is being debugged. To do this, the malware can check whether its own code is set to break the point, or directly through the system to detect the debugger.
1. Breakpoint
In order to detect if its code is set to a breakpoint, malware can find the instruction opcode 0xcc (the debugger uses the directive to take control of the malware at the breakpoint), which can cause a sigtrap. If the malware code itself establishes a separate handler, the malicious software can also set up a pseudo breakpoint. In this way, malicious software can continue to execute its instructions when a breakpoint is set.
Malicious software can also try to overwrite breakpoints, for example, some viruses use a reverse decryption loop to overwrite a breakpoint in a virus. Conversely, some viruses use Hamming code to correct itself. The Hamming code allows the program to detect and modify errors, but here it enables the virus to detect and clear breakpoints in its code.
2. Calculate the Checksum
The malware can also compute its own checksum, and if the checksum changes, the virus assumes that it is being debugged and that its code has been placed inside the breakpoint. Vampire is an anti-counter debugging tool that can be used to evade breakpoint detection. Vampire achieves the goal by maintaining a breakpoint table in memory that records all breakpoints that have been set. The program consists of a page fault handler (PFH), a generic protection fault handler (GPFH), a single-step handler, and a framework API. When a breakpoint is triggered, control is either passed to the PFH (processing a breakpoint that is set in code, data, or memory-mapped I/O) or passed to GPFH (handling legacy I/O breakpoints). The Single-step handler holds breakpoints so that breakpoints can be used more than once.
3. Testing the Debugger
There is a simple way to detect a debugger on a Linux system, as long as you call Ptrace, because you cannot call ptrace more than two times for a particular process. In Windows, if the program is currently in the debug state, the system call Isdebuggerpresent will return 1, otherwise return 0. This system call simply checks a flag bit, and when the debugger is running, the flag bit is placed 1. This check can be done directly through the second byte of the process environment block, and the following code shows this technique:
mov eax, fs:[30h]
move eax, Byte [eax+2]
Test eax, EAX
Jne @DdebuggerDetected
In the above code, EAX is set to PEB (the process environment block), then accesses the second byte of the PEB and moves the contents of the byte into the eax. You can complete this test by looking at whether the EAX is zero. If zero, there is no debugger, otherwise there is a debugger.
If a process is created for a debugger that runs in advance, the system sets flags for the heap action routines in Ntdll.dll, which are Flg_heap_enable_tail_check, flg_heap_enable_free_ Check and Flg_heap_validate_parameters. We can check these flags with the following code:
mov eax, fs:[30h]
mov eax, [eax+68h]
and EAX, 0x70
Test eax, EAX
Jne @DebuggerDetected
In the above code, we still access the PEB, and then we can see if the debugger exists by checking the flags by PEB the address plus the offset 68h to the starting position of the flags used by the heap action routines.
Checking for flags such as Forceflags in the head of the heap can also detect if a debugger is running, as follows:
mov eax, fs:[30h]
mov eax, [eax+18h];p rocess Heap
mov eax, [eax+10h]; Heap Flags
Test eax, EAX
Jne @DebuggerDetected
The code above shows us how to access the heap and heap flags of the process through PEB offsets, and by examining them we can see whether the force flag has been set to 1 in advance by the currently running debugger.
Another way to detect a debugger is to use ntqueryinformationprocess to call this system. We can call this function by setting Processinformationclass to 7来, which references Processdebugport, and if the process is being debugged, the function returns-1. The sample code is shown below.
Push 0push 4push offset Isdebuggedpush 7; Processdebugportpush-1call ntqueryinformationprocesstest eax, Eaxjne @ExitErrorcmp isdebugged, 0jne @DebuggerDetected
In this case, the ntqueryinformationprocess parameters are first pressed onto the stack. These parameters are described as follows: The first is a handle (0 in this case), the second is the length of the process information (in this case 4 bytes), followed by the Process information category (7 in this case, Processdebugport), and the next is a variable that returns information about the debugger. If the value is a value other than 0, then the process is running under a debugger; otherwise, everything is fine. The last parameter is the return length. The return value after using these parameters to invoke Ntqueryinformationprocess is in isdebugged. It then tests whether the return value is 0.
In addition, there are other ways to detect the debugger, such as checking whether the device list contains the name of the debugger, checking for the presence of a registry key for the debugger, and scanning for memory to check for code that contains the debugger.
Another very similar approach to EPO is to notify the PE loader to refer to the program's entry point through the thread local memory (TLS) table entry in the PE header. This causes the code in TLS to be executed first, rather than reading the entry point of the program first. As a result, TLS can complete the instrumentation required for reverse debugging at program startup. Booting from TLS allows the virus to start running before the debugger starts, because some debuggers are cut in at the main entry point of the program.
4. Probe Single Step execution
The malware can also detect the debugger by checking for stepping. To detect stepping, we can put a value into the stack pointer and see if the value is still there. If the value is there, this means that the code is being executed in steps. When the debugger steps through a process, it needs to push some instructions into the stack when it takes control and stack it before executing the next instruction. So, if the value is still there, it means that the other running processes are already using the stack. The following example code shows how malware detects stepping through the stack state:
Mov bp,sp; Select stack pointer
Push Ax, pressing AX into stack
Pop ax; Select the value from the stack
Cmp word ptr [bp-2],ax; comparison with values in the stack
Jne Debug; If different, the debugger is found.
As noted in the note above, a value is pressed onto the stack and then ejected. If there is a debugger, then the stack pointer –2 the value on the position that is different from the value of the pop-up stack, and the appropriate action can be taken.
5. Detect speed decay at run time
Malicious code can also detect the debugger by observing whether the program slows down at run time. If the program slows down significantly at run speed, it probably means that the code is stepping through. So if the timestamp of two calls is very different, then the malware needs to act accordingly. The Linux tracking Kit LTTNG/LTTV tracks the virus by observing the deceleration problem. When LTTNG/LTTV a tracking program, it does not need to add breakpoints or perform any analysis while the program is running. In addition, it uses a lock-free reentrant mechanism, which means it does not lock any Linux kernel code, even if the kernel code is the part of the program that is being tracked, so it does not slow down and wait for the tracked program.
6. Directive prefetching
If the malicious code tampered with the next instruction in the instruction sequence and the new instruction was executed, then a debugger is running. This is the result of an instruction prefetch: if the new instruction is prefetch, it means that there are other programs in the process's execution. Otherwise, the prefetching and execution should be the original instructions.
7. Self-modifying code
Malware can also allow other code to modify itself (by modifying other code itself), an example of which is hdspoof. The malware first initiates some exception-handling routines and then eliminates them in the process of running. As a result, if anything fails, the running process throws an exception, and the virus stops running. In addition, it can sometimes tamper with exception handling routines by purging or adding exception handling routines during run time. Below is the code that hdspoof clears all exception-handling routines except the default exception-handling routines.
Exception handlers before:
0x77f79bb8 ntdll.dll:executehandler2@20 + 0x003a0x0041adc9 hdspoof.exe+0x0001adc90x77e94809 __except_handler3
Exception handlers after:
0x77e94809 __except_handler3
0X41B770:8B44240C mov eax,dword ptr [esp+0xc]0x41b774:33c9 xor ecx,ecx 0x41b776:334804 xor Ecx,dword ptr [eax+0x4]0x41b 779:334808 xor Ecx,dword ptr [eax+0x8]0x41b77c:33480c xor Ecx,dword ptr [eax+0xc]0x41b77f:334810 xor Ecx,dword ptr [eax +0x10]0x41b782:8b642408 mov esp,dword ptr [esp+0x8]0x41b786:648f0500000000 pop dword ptr fs:[0x0]
The following is the code for Hdspoof to create a new exception handler.
0x41f52b:add DWORD ptr [ESP],0X9CA
0x41f532:push DWORD ptr [DWORD ptr fs:[0x0]
0x41f539:mov DWORD ptr fs:[0x0],esp
8. Overwrite debugger information
Some malware uses a variety of techniques to overwrite debugging information, which can cause the debugger or the virus itself to malfunction. By hooking the interrupt int 1 and int 3 (int 3 is the operation code used by the debugger 0xCC), the malware may also cause the debugger to lose its context. This is no hindrance to a virus that is running properly. Another option is to hook up various interrupts and invoke additional interrupts to run the virus code indirectly.
Here's the tequila virus to hook int 1 code:
New_interrupt_one:
Push BP
MOV bp,sp
CS CMP b[0a],1; MASM MoD. Needed
Je 0506; MASM mod. Needed
CMP W[BP+4],09B4
JA 050b; MASM mod. Needed
Push AX
Push ES
Les ax,[bp+2]
CS mov w[09a0],ax; MASM mod. Needed
CS mov w[09a2],es; MASM mod. Needed
CS mov b[0a],1
Pop es
Pop ax
and W[bp+6],0feff
Pop bp
Iret
Typically, the hook routine is set to Iret when the debugger is not installed. V2PX uses hooks to decrypt virus bodies with int 1 and int 3. the int 1 and int 3 vectors are used continuously during the code run, and the calculation is done through the interrupt vector table.
Some viruses also empty the debug registers (DRN content). There are two ways to do this, one is to use System invoke Ntgetcontextthread and Ntsetcontextthread. Instead, it causes an exception, modifies the thread context, and then resumes normal operation with the new context, as follows:
Push Offset Handler
Push DWORD ptr fs:[0]
MOV Fs:[0],esp
xor eax, EAX
div eax; Generate exception
Pop fs:[0]
Add ESP, 4
; Continue execution
;...
Handler
mov ecx, [esp+0ch]; Skip Div
Add DWORD ptr [ecx+0b8h], 2; Skip Div
mov dword ptr [ecx+04h], 0; Clean dr0
mov dword ptr [ecx+08h], 0; Clean DR1
mov dword ptr [ecx+0ch], 0; Clean DR2
mov dword ptr [ecx+10h], 0; Clean DR3
mov dword ptr [ecx+14h], 0; Clean DR6
mov dword ptr [ecx+18h], 0; Clean DR7
xor eax, EAX
Ret
The first line of code presses the handler's offset into the stack to ensure that its own handlers gain control when the exception is thrown. It is then set up, including setting the EAX to 0 in its own different or own way, to transfer control to the handler. The div eax instruction causes an exception because the EAX is 0, so the ax will be divided by 0. The handler then skips the division instruction, empties the DR0-DR7, and also puts the EAX 0, indicating that the exception will be processed and then resumed.
9. Unlock Debugger Threads
We can disassemble the thread from the debugger through the system call NtSetInformationThread. To do this, set Threadinformationclass to 0x11 (Threadhidefromdebugger) to invoke NtSetInformationThread, which, if present, will remove the program's thread from the debugger. The following code is an example:
Push 0
Push 0
Push 11h; Threadhidefromdebugger
Push-2
Call NtSetInformationThread
In this example, the NtSetInformationThread parameter is first pressed onto the stack, and then called to remove the program's thread from the debugger. This is because 0 is used for thread information length and thread information, the pass-2 is used for thread handles, and 11h is passed to the thread information category, where the value represents Threadhidefromdebugger.
10. Decryption
Decryption can be done in a variety of ways to prevent debugging. Some decryption relies on a specific execution path. If the execution path is not followed, for example, by starting a debugger somewhere in the program, the decryption algorithm uses a wrong value, so the program cannot decrypt itself correctly. This technique is used by hdspoof.
Some viruses use the stack to decrypt their code, and if you use the debugger on this virus, it can cause decryption to fail because the stack is used for int 1 when debugging. An example of using this technique is the W95/sk virus, which decrypts and constructs its code in the stack; another example is the Cascade virus, which uses the stack pointer register as a decryption key. The code looks like this:
Lea Si, Start; Position to decrypt
mov sp, 0682; Length of encrypted body
Decrypt:
xor [Si], si; Decryption Key/counter 1
xor [Si], SP; Decryption Key/counter 2
Inc si; Increment one counter
Dec sp; Decrement the other
JNZ Decrypt; Loop until all bytes are decrypted
Start:; Virus body
The comments in the code above are well illustrated for how the Cascade virus uses the stack pointer to decrypt the virus body. Instead, the Cryptor virus stores its keys in the keyboard buffer, which can be corrupted by the debugger. Tequila uses the decryption code as the decryption key, so if the decryption device is modified by the debugger, then the virus cannot be decrypted. The following is the code that tequila uses to decrypt:
Perform_encryption_decryption:
MOV bx,0
MOV si,0960
MOV cx,0960
MOV Dl,b[si]
XOR B[BX],DL
Inc si
Inc BX
CMP si,09a0
JB 0a61; MASM MoD. Needed
MOV si,0960
loop 0a52; MASM MoD. Needed
Ret
The_file_decrypting_routine:
Push CS
Pop ds
MOV bx,4
MOV si,0964
MOV cx,0960
MOV Dl,b[si]
Add B[BX],DL
Inc si
Inc BX
CMP SI,09A4
JB 0a7e; MASM MoD. Needed
MOV si,0964
loop 0a6f; MASM MoD. Needed
JMP 0390; MASM MoD. Needed
A new type of reverse debugging technology is being studied for the future, one of which is about multiple computers, because one of the multiple processors is idle when debugging. This new technology uses parallel processing techniques to decrypt code.
Ii. retrovirus
Retrovirus tries to disable anti-virus software, such as by carrying a list of process names and killing those processes that are running with the same name as the table. Many retrovirus also kick the process out of the startup list so that the process cannot be started during system boot. This type of malware will also try to squeeze the anti-virus software's CPU time, or prevent anti-virus software from connecting to the anti-virus software company's servers so that it cannot update the virus library.
Third, Hybrid technology
W32. The Gobi virus is a polymorphic retrovirus that combines EPO with some of the other reverse debugging techniques. The virus also opens a backdoor on TCP port 666.
Simile (also known as metaphor) is a very famous complex virus that contains about 14,000 lines of assembly code. The virus uses EPO by looking for an API call to ExitProcess (), which is also a polymorphic virus because it uses polymorphic decryption techniques. Its 90% code is for polymorphic decryption, and the body of the virus and the polymorphic decryption device will be placed in a half random place each time a new file is infected. The first payload of simile is activated only in March, June, September, or December. The 17th variants A and B of these months show their messages. Variant C displays its message on the 18th day of these months. The second payload in Variant A and B is activated only on May 14, while the second payload in Variant C is activated only on July 14.
Ganda is a retrovirus using the EPO. It examines the list of startup processes and replaces the first instruction of each startup process with a return instruction. This makes all anti-virus programs useless.
Iv. Summary
In this article, we introduce some of the reverse debugging techniques that malicious software uses to hinder reverse engineering, and introduce a combination of retrovirus and various counter detection techniques. We should have a good understanding of these technologies, only in this way can be more effective for the malicious software dynamic detection and analysis.