Background
The previous article introduced the principle of xorstr and the code of the minimal verification concept. This article looks at how to restore this technology that has been widely used in various malicious samples and security components. If you haven’t read the previous suggestion, Read it first to understand its implementation before reading this article
xorstr’scurrent situation
As the application of related technologies becomes more and more widespread, various attack samples use this tool, and threat sample analysis becomes more and more time-consuming. This is why a restoration tool is needed to combat the above-mentioned obfuscation technology. The application of two open source restoration tools, flare-floss and AntiXorstr, greatly reduces the difficulty of restoring such binary hidden strings.
Restore PlanAnalysis
Flare-floss is an automated binary string heuristic search tool for virus analysis developed and open sourced by mandiant. Flare-floss provides two restoration logics (stack string & tight string) for this type of encryption method. Based on different assumptions, but they can all be used to handle the above encryption, a brief analysis summary of his implementation principle is given below.
stack string: This reduction method of flare-floss is based on a very broad assumption, that is, this string must be based on the stack, constructed and decrypted on the stack. Therefore, he uses simulated execution to simulate the execution of each function one by one in the assembly code, and performs a full dump of the current stack when encountering a function call instruction. Finally, he uses the string plaintext algorithm to find suspected plaintext strings in the dump. Save the results.
Because its assumptions are too broad, it has almost 100% coverage of current open source xorstr-like projects. However, the overly broad assumptions lead to a large number of false positives. For security analysis, too much junk information interferes with the correct analysis. Judgment, this false positive is specifically marked in its code as “don’t run this on functions with tight loops as this will likely result in FPs”
floss-stack string | floss-stack string |
---|---|
Coverage | Excellent+ |
Bypass difficulty | Excellent+ |
Error Report rate | Poor- |
Accuracy | Poor- |
floss-tight string | floss-tight string |
---|---|
Coverage | Excellent- |
Bypass difficulty | Medium + |
Error Reporting rate | Medium + |
Accuracy | Poor- |
AntiXorstr | AntiXorstr |
---|---|
Coverage | Medium + |
Bypass difficulty | Excellent- |
False alarm rate | Excellent+ |
Accuracy | Excellent+ |
Tight string bypass
In the process of analyzing the tight string logic of floss, I found that his assumption is not actually necessary for stack strings, but it is indeed a feature that must exist in almost all current open source implementations, that is, the decryption function flow chart appears as a loop. form. Therefore, to bypass the floss-tight string is to implement a string decryption function that does not form a loop. First, let’s take a look at the disassembly flow chart characteristics of the current conventional string decryption logic. The demo is as follows
The loc_1400010A0 here is a loop Block, and the code in the Block is the assembly code of the decrypt function that decrypts the original data in the for loop. Here, we can bypass this restoration method without generating a loop inside the decrypt function. So how to eliminate the loop? Think about it here using the idea of template programming. The recursive expansion of templates in loops can be eliminated at compile time. The final desired effect is as follows
__forceinline char* decrypt() {<!-- --> for (auto index = 0; index < N; index + + ) {<!-- --> encBuffer[index] -= 1; } return encBuffer; } //N = 5 __forceinline char* decrypt_noloop() {<!-- --> encBuffer[0] -= 1; encBuffer[1] -= 1; encBuffer[2] -= 1; encBuffer[3] -= 1; encBuffer[4] -= 1; return encBuffer; }
The rest is how to use the C++ template to generate the decrypt_noloop code, use recursive expansion to generate it, and make a specialized termination for N=0 to eliminate the loop. There are also some details that will not be expanded here due to space limitations. The DEMO has been implemented. Open source: xorstr_s.h
test demo
void test() {<!-- --> printf(Enc("Samsung\ ")); wprintf(Enc(L"Apple\ ")); printf(Enc("Xiaomi\ ")); wprintf(Enc(L"Oppo Group\ ")); printf(Enc("vivo\ ")); wprintf(Enc(L"Transsion\ ")); std::cout << Enc("Honor") << std::endl; std::wcout << Enc(L"Realme") << std::endl; std::cout << Enc("Motorola") << std::endl; std::wcout << Enc(L"Huawei") << std::endl; std::cout << Enc("Others") << std::endl; }
Test results: STACK & TIGHT bypassed, DECODED mode restored part of the
──────────────────── FLOSS STACK STRINGS ──────────────────── ──────────────────── FLOSS TIGHT STRINGS ──────────────────── ────────────────────── FLOSS DECODED STRINGS ────────────────────── Samsung Apple Xiaomi Oppo Group vivo Transsion Honor
More robust bypass strategy
The xorstr_s written above through detailed analysis of the floss restoration strategy does not seem to be very robust. It is too costly to implement a customized bypass solution just for an open source tool. So is there a more robust anti-reduction method? For the time being, there is There are two methods, the core principle of one of which is: “Heap-based plaintext expansion”, which makes Floss’s mode of monitoring heap plaintext completely invalid.
Those who have read the previous article should know that the string ciphertext is stored in the stack, but it does not have to be decrypted on the spot. It is completely possible to read only the stack data and write the decrypted plaintext to the heap, and use the temporary object’s The destructor can complete the release of the heap. The DEMO implementation has been open source: xorstr_h.h. The effect of testing FLOSS is as follows
FLOSS STACK STRINGS ──────────────────── o]QOIR[6< }<L<L<P<Y<6<<< dU]SQU6< s<L<L<S< <{<!-- --><N<S<I<L<6<<< JUJS6 h<N<]<R<O<O<U<S<R<6<<< tSRSN n<Y<]<P<Q<Y<<< qSHSNSP]< t<I<]<K<Y<U<<< sHTYNO< ──────────────────── FLOSS TIGHT STRINGS ──────────────────── ────────────────────── FLOSS DECODED STRINGS ────────────────────── o]QOIR[6<
Test results: Floss bypass in all modes