[Edited: The technique discussed in this diary is not mine and has been used without proper citation of the original author]
For bad guys, the implementation of techniques to prevent Security Analysts to perform their job is key! The idea is to make our life more difficult (read: "frustrating"). There are plenty of techniques that can be implemented but it's an ever-ongoing process. Note that this topic is covered in the SANS FOR610 training.
An anti-debugging technique is based on the following steps:
1. To try to perform a specific action
The example that I'll cover in this diary was the subject of a thread on a security mailing list and I found it interesting enough to be reported here (I'm just wrapping up the information here, this is not a personal finding).
The sample has the following SHA256 hash: 68af250429833d0b15d44052637caec2afbe18169fee084ee0ef4330661cce9c.
If you run the sample into a debugger, you'll see that it exits with an exception error but, when executed in a sandbox, it works like a charm. Let's see what's the magic behind this.
The exception occurs in a function
First, we have an obfuscation technique based on stack strings but with a shift of characters:
The string 'HgwZjxzqxxP...' can be decoded with this Python code block:
>>> s='HgwZjxzqxxP' >>> d='' >>> i=1 >>> for c in s: ... d = d + chr(ord(c)-i) ... i=i+1 ... >>> d 'GetVersionE'
The question is now: why is this pointer set to NULL? We know how the anti-debugging works but how is it triggered?
In the function
"If this parameter is zero and CreateFileW succeeds, the file or device cannot be shared and cannot be opened again until the handle to the file or device is closed".
This causes a problem with the debugger and CreateFileW() fails (RAX - the return value - contains 0xFFFFFFFF). The file won't be read and the execution continues until
To bypass this problem, an interesting technique was proposed in the discussion: Let's duplicate kernel32.dll on the filesystem and rename it kernel33.dll. Then, just before the call to
$ppid = (gwmi win32_process | ? processid -eq $PID).parentprocessid; $proc = Get-Process -FileVersionInfo -Id $ppid; Stop-Process -Force -ErrorAction SilentlyContinue -Id $ppid; $buff = [byte]@(, 0 * 1mb); Set-Content -Path $proc.FileName -Force -Confirm:0 -Value $buff; Remove-Item -Path $proc.FileName -Force -Confirm:0
Xavier Mertens (@xme)
May 22nd 2021
May 22nd 2021
3 weeks ago