# Resolver (reverse medium, 16 solves)
## Challenge
You are trying to get into a malware development forum and an administrator gives you this challenge to solve to get in. According to him, this function is used for dynamic resolving. He wants you to give him the values to pass as parameters to resolve the following functions:
GetDateFormatWWorker (val1)
IsWow64GuestMachineSupported (val2)
SetThreadPreferredUILanguages (val3)
Format : Hero{0xval1:0xval2:0xval3}
## Answer
We're given an ASM listing screenshot of IDA. You'll find below an annotated
transcript. This code is a custom GetProcAddress using function hashing. This
hashing technique is used by malware developpers to evade security solutions
because imports don't directly rely on the API literal but on hash of it,
hence, security solutions cannot automatically find the API names on the code or
on the regular import table.
It begins by finding the address of the mapped kernel32.dll using the PEB which
in 32-bit mode is accessible at `fs+0x30`. It then iterates the export table and
starts computing hashes of API names.
```
resolve:
push ebp
mov ebp, esp
sub esp, 10h
mov eax, large fs:30h ; TIB+0x30 -> PEB
mov eax, [eax+0Ch] ; PEB_LDR_DATA *Ldr
mov eax, [eax+14h] ; LIST_ENTRY InMemoryOrderModuleList (FLink)
mov eax, [eax] ; (Flink)
mov eax, [eax] ; (Flink)
mov edi, [eax+10h] ; LDR_MODULE's BaseAddress Kernel32
mov eax, [edi+eax+78h] ; 0x78 is PE offset for export table
add eax, edi ; absolute base addr
mov edx, [eax+20h] ; AddressOfNames offset
mov ebx, [eax+1Ch] ; AddressOfFunctions offset
add edx, edi ; abs
mov eax, [eax+18h] ; NumberOfNames offset
add ecx, edi ; abs
mov [ebp+var_4], edx ; stack store AddressOfNames
mov [ebp+var_8], ecx ; stack store AddressOfFunctions
mov [ebp+var_C], eax ; stack store NumberOfNames
xor ecx, ecx
test eax, eax
jz short _L0
_L1:
mov eax, [edx+ecx*4] ; address of name
add eax, edi ; abs
push ebx
push ecx
mov esi, eax
xor rdx, rdx
jmp short _L3
_L2:
movsx ecx, bl
rol edx, 0Eh ; rotate left accumulator
cmp bl, 61h ; 'a'
lea eax, [ecx-20h] ; toupper
cmovl eax, ecx ; transform to uppercase if necessary
add edx, eax ; add to accumulator
inc esi ; inc name ptr
_L3:
mov bl, [esi] ; get letter
test bl, bl ; end of api name
jnz short _L2
mov eax, edx ; L2 computed value in edx
pop ecx
pop ebx
cmp eax, [ebp+arg_0]
jz short _L4
mov edx, [ebp+var_4] ; AddressOfNames
inc ecx
cmp ecx, [ebp+var_c] ; NumberOfNames
jb short _L1 ; There are more names to iterate
_L0:
xor eax, eax
jmp short _END
_L4: rva to va ?
mov eax, [ebp+var_8] ; AddressOfFunctions
movzx eax, word ptr [eax+ecx*2] ; get ordinal
mov eax, [ebx+eax*4] ; VMA
add eax, edi ; add base addr of kernel32
_END:
mov esp, ebp
pop ebp
retn
```
The hashing algorithm in `_L2` mainly consists of a `rol` and an `add`. We can
easily replicate it in C:
```c
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <stdint.h>
#define ROL(S,i) (((S)<<(i)) | ((S)>>(32-(i))))
int resolve(char*s) {
uint32_t acc = 0; // edx might not be zeroed
for (unsigned i = 0 ; i < strlen(s) ; i++)
{
acc = ROL(acc, 0xe);
acc += toupper(s[i]);
}
printf("0x%x", acc);
}
int main() {
printf("Hero{");
resolve("GetDateFormatWWorker");
printf(":");
resolve("IsWow64GuestMachineSupported");
printf(":");
resolve("SetThreadPreferredUILanguages");
printf("}\n");
}
```
And the flag: `Hero{0xe3232703:0x89291c8b:0xac881638}`