I drafted this article long time ago, shortly after releasing an overview of Kpot, but I never followed-up on this, anyhow, recently I had some time and thought to polish it a bit and just publish.
I will jump straight to the point, but, for those of you that are not familiar with Qiling just have a look at the repository and documentation portal, you won’t be disappointed!
Let it be Ghidra
I take as granted that you had a look at the previous analysis and have an idea how the decryption function was discovered and reversed, the whole point of working with Qiling in this scenario is - as lazy reverser - to let the tool do the heavy lifting and let us have the rest of the fun.
For this version of Kpot, two emulation approaches are possible, but the techniques introduced here, will serves you well for any malware that relies on the same code implementation.
The choice
Opt - 1. Since strings gets decrypted in bulk (within one huge single function), soon after the main entry in the code, emulating the wrapper function that hosts all calls to the mw_func_string_decrypt, could be a quick win. Intercepting all MOV operations, when the content of EAX is moved into the global array, would grant access to the decrypted string.

In this case, it becomes trivial to check for the pattern {a3 ?? 5? 41 00 } and build emulation around that, but we will go down another road instead…
Opt - 2. Emulate only the function in charge of the string decryption and craft all the expected parameters

We will investigate this 2nd method, since more precise and, as far as I could see, no one showed how to do this with Qiling, which is not the case for the first strategy.
First thing first, let’s do a quick recap about the decryption function, which uses __cdecl calling convention and it takes three parameters,
- Decryption key
- Encrypted string
- Length of the encrypted string
| |
We do now a fast forward and assume the following (yet again, check the previous blog, which explains all steps how we reached this point):
- all xref calls to the string decryption function, were identified (via scripting) with Ghidra
- for every xref call, parameters (decryption key, encrypted string and length of the same) were extracted
- finally, everything was stored in a basic data structure, such as, a list of strings and tuples
| |
after harvesting all the required details, the buffer structure, would look like this
| |
Maximum effort
At this point, we are just missing one single step, the emulation part, since all the details needed to accomplish Opt - 2 were collected and formatted in a way to be consumed by Qiling.
Main points, aka, what we need to make Qiling work for us:
1 Identify the decryption function, start and ending addresses, which in this case are, 0x405623 and 0x40567d
2 define, where in the malware code, a hook will be placed, e.g. 0x40567c

This is needed, since if you recall before exiting, the decrypt function will store the deobfuscated string in the EAX register, and our goal is to extract this value before it gets overwritten by some other operation.
3 Since only one function is emulated and not the whole binary, and the same (function) uses __cdecl calling convention, the stack needs also to be prepared, which requires:
PUSHlength of the encrypted stringPUSHencrypted stringPUSHdecryption keyPUSHreturn address, to return once the decryption function has completed
let’s head to the code part
| |
Below, how Ghidra’s listing view looks like after updating the labels with the above script.

One last note, in the example, the start and end addresses of the target function were hardcoded, but everything can be implemented more dynamically, leveraging a YARA rule to track down the function, something like the one below
rule kpotv1_decrypt_strings_function
{
meta:
author = "_raw_data_"
tlp = "WHITE"
version = "1.0"
created = "2020-04-13"
modified = "2020-04-13"
description = "Kpotv1 string decryption routine"
reference = "https://raw-data.gitlab.io/post/kpotv1/"
strings:
$dec_str_fun = { 5? 8b ?? 5? 5? 5? 8b 75 10 8d 46 01 57 50 e8 ?? ?? ?? ??
33 db 59 8b f8 85 f6 74 ?? 8b 45 08 2b c7 89 45 fc 8b 4d
0c 8d 34 3b e8 ?? ?? ?? ?? 8b c8 33 d2 8b c3 f7 f1 8b 45
0c 8b 4d fc 8a 04 02 32 04 31 43 88 06 3b 5d 10 72 ?? 8b
75 10 c6 44 37 ff 00 8d 4? }
condition:
$dec_str_fun
}
From here, calculating the max and min addresses within the function becomes trivial and could be implemented with a snippet like this
| |