Static-Analysis on this program didn’t reveal much. There must be a better way to approach this…
Static Analysis#
Отриманий файл - PE execiteble для Windows 64-bit
1$ file *
2partialencryption.exe: PE32+ executable for MS Windows 6.00 (console), x86-64, 5 sectionsPacker#
Містить невелику кількість imports, що вказують на пакуваня (VirtualAlloc VirtualProtect VirtualFree) та на anti-dynamic analysis:
- IsDebuggerPresent - перевірка чи програма працює під дебагером
- QueryPerformanceCounter та GetSystemTimeAsFileTime - можуть використовутися для вимирювання часу між інструкціями
1VirtualAlloc
2VirtualProtect
3VirtualFree
4QueryPerformanceCounter
5GetCurrentProcessId
6GetCurrentThreadId
7GetSystemTimeAsFileTime
8InitializeSListHead
9RtlCaptureContext
10RtlLookupFunctionEntry
11RtlVirtualUnwind
12IsDebuggerPresent
13UnhandledExceptionFilter
14SetUnhandledExceptionFilter
15IsProcessorFeaturePresent
16GetModuleHandleW
17KERNEL32.dllReversing#
by static analysis i found that used aeskeygenassist та aesdeclast instructions. Це вказує на використання процесорних розширень Intel AES-NI для криптографічних операцій
- aeskeygenassist used to assist in generating round keys on-the-fly
- aesdeclast performs the final round of the decryption state

Dynamic Analysis#
just running#
i tried run program
C:\Users\f\Desktop>partialencryption.exe aaaaaaaa
Nope
C:\Users\f\Desktop>partialencryption.exe aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
NoRunning over x64dbg#
I placed a breakpoint on the VirtualAlloc call to identify where data is being written in memory. I set a hardware breakpoint on that address, resumed execution, but only received a Nope message. This indicated that a check was failing before the program jumped to the decrypted data.

I then executed the program with a longer input string (e.g., aaa...) to observe its behavior under those conditions.

In this case, the program began checking individual characters of the flag.
1...[snip]...
2| mov rax,qword ptr ds:[rdx+rax] |
3| movsx eax,byte ptr ds:[rax+rcx] |
4| cmp eax,48 | 48:'H'
5...[snip]...
6| mov rax,qword ptr ds:[rdx+rax] |
7| movsx eax,byte ptr ds:[rax+rcx] |
8| cmp eax,54 | 54:'T'
9...[snip]...
10| mov rax,qword ptr ds:[rdx+rax] |
11| movsx eax,byte ptr ds:[rax+rcx] |
12| cmp eax,42 | 42:'B'
13...[snip]...
14| mov rax,qword ptr ds:[rdx+rax] |
15| movsx eax,byte ptr ds:[rax+rcx] |
16| cmp eax,7B | 7B:'{'
17...[snip]...
18| imul rcx,rcx,15 | rcx:putchar
19| mov rdx,qword ptr ss:[rsp+48] | rdx:exit
20| mov rax,qword ptr ds:[rdx+rax] |
21| movsx eax,byte ptr ds:[rax+rcx] |
22| cmp eax,7D | 7D:'}}'
23...[snip]...Continuing debugging, I found three identical blocks of code that handle decryption and execution:
1| mov r8d,8000 |
2| xor edx,edx |
3| mov rcx,qword ptr ss:[rsp+30] |
4| call qword ptr ds:[<VirtualFree>] |
5| xor eax,eax |
6| cmp eax,1 |
7| je partialencryption.7FF62E0F149A |
8| mov edx,1E0 | ## size 480 bytes
9| lea rcx,qword ptr ds:[7FF62E0F42E0] | ## encryption data source
10| call partialencryption.7FF62E0F1050 | ## decrypting payload into memory
11...[snip]...
12| call qword ptr ss:[rsp+58] | ## jumps directly to the start of that new decrypted codeBy placing breakpoints on these dynamic call qword ptr ss:[rsp+??] instructions, we intercepted the decrypted logic for each stage.
call qword ptr ss:[rsp+58]:
1...[snip]...
2| mov rax,qword ptr ds:[rdx+rax] |
3| movsx eax,byte ptr ds:[rax+rcx] |
4| cmp eax,57 | 57:'W'
5...[snip]...
6| cmp eax,33 | 33:'3'
7...[snip]...
8| cmp eax,33 | 33:'3'
9...[snip]...
10| cmp eax,52 | 52:'R'
11...[snip]...
12| cmp eax,52 | 52:'R'
13...[snip]...
14| cmp eax,5F | 5F:'_'By debugging the remaining two parts, I obtained the final flag: HTB{W3iRd_RUnT1m3_DEC}.