---
# System prepended metadata

title: 'Resolver (reverse medium, 16 solves)'

---

# 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}`
