[CTF Series #10] Reversing Shadow Clone With Ghidra

This is a Windows C++ reversing challenge created by me for the University CTF challenge. Will using Ghidra, xdbg64 and brainz to solve it.

This challenge is inspired by the malware which perform code injection in its own child process and malware which create mutex to control the execution flow. Don’t Sum Ting Wrong here and there plz 😋


The sample will duplicate self process and pipe out the to read to file’s text stream from parent to child process.

Later it will check does the text.txt exist in the same directory.

If yes, then it will continue to read content of the file and check whether the content has length of 17 (Hex: 0x11).

If not, it will print out my custom error message 😜

Verification will be done in the child process and it will print out the congratz message if all the conditions were fulfilled.

For me, its is good to solve this challenge through both static and dynamic analysis.

It is fun the analyze this sample dynamically.

Static Way

First go find the out the condition which prints out the congratz message.

It seems weird at first since those local_* variable still remain unknown, continue the analysis and you will find out the code segment which contains the flag. However, it is scrambled and contains missing strings in between.

Try to rearrange the flag fragment to see what does the actual flag structure looks like.

local_30 == 'x'
local_31 == 'r'
local_32 == 'e'
local_33 == 'b'
local_34 == 'y'
local_35 == 'c'
local_36 == '2'
local_37 == ' '
local_38 == 'm'
local_39 == ' '
local_3a == 'n'
local_3b == ' '
local_3c == '1'
local_3d == ' '
local_3e == 'M'
local_3f == 's'
local_40 == 'f'

Hmm… since the flag format for flag is fs…cyberx then it can be guess that the first flag strings is started from local_40 until local_30.

(int) local_37 — (int)local_36 == 1
(int) local_37–2 = 1
(int) local_37 = 0x33 (Chr: 3)
local_3b + -(int)local_37 == 0x1
local_3b + -3 = 1
local_3b = 0x34 (Chr: 4)
pcVar2 = (code *)(int)local_3b
unaff_EBX = (HANDLE)((int)local_3d — (int)pcVar2);
unaff_EBX == (HANDLE)0x31
local_3d — 4 == 0x31
local_3d = 0x65 (Chr: e)
(int)local_3d — (int)local_39 == 0x21
0x65 — (int)local_39 == 0x21
(int)local_39 = 0x44 (Chr: D)

Dynamic Way

Will only highlight the notable steps only.

Stop at the assembly code that calls resumeThread()

Breakpoint at resumeThread()

Open the a new debugger and attach to the child process and set breakpoint in the .text section of the code so that when you resume the thread it will stop the full execution of the code.

Step over the resumeThread() in parent process and move your focus on the child process.

Eventually you will find out the child process will goes through the flag validation function meanwhile the parent process will only load the file. This is because of the CreateMutex() . First, the parent process will launch and create the mutex Ujikop . After the child process created. It will check whether the mutex is created. If yes, it will go to another function which is validate the flag strings.

After that, some validation stuffs and congratz message get.

After Thoughts

The main purpose of this challenge is to let the participant to understand how to perform dynamic analysis when dealing with samples which using process injection eventhough it can be solve easily by using static analysis 🤣.





Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store