Case op13 · evaluated model OpenAI · judges ClaudeAI, GeminiAI, OpenAI

Selection reason: stratified_random

Understanding point

CRC32 hashing
Code snippet · op13/code1.txt
int __cdecl sub_10001561(int a1, int a2)
{
  int v2; // edx
  unsigned int v4; // ebx
  char v5; // ah
  int v6; // [esp+18h] [ebp-4B4h]
  int v7; // [esp+34h] [ebp-498h]
  int v8; // [esp+38h] [ebp-494h]
  unsigned int v9; // [esp+40h] [ebp-48Ch]
  int v10; // [esp+44h] [ebp-488h]
  unsigned __int16 *v11; // [esp+4Ch] [ebp-480h]
  int v12; // [esp+50h] [ebp-47Ch]
  unsigned int v13; // [esp+70h] [ebp-45Ch]
  unsigned int v14; // [esp+74h] [ebp-458h]
  int v15; // [esp+78h] [ebp-454h]
  int v16; // [esp+7Ch] [ebp-450h]
  unsigned int v17; // [esp+80h] [ebp-44Ch]
  int v18; // [esp+84h] [ebp-448h]
  int v19; // [esp+8Ch] [ebp-440h]
  _DWORD v20[256]; // [esp+90h] [ebp-43Ch]
  char v22; // [esp+497h] [ebp-35h]
  unsigned __int64 v23; // [esp+498h] [ebp-34h]
  bool v24; // [esp+4A7h] [ebp-25h]
  unsigned int v25; // [esp+4A8h] [ebp-24h]
  unsigned int v26; // [esp+4ACh] [ebp-20h]
  int v27; // [esp+4B0h] [ebp-1Ch]
  int v28; // [esp+4B4h] [ebp-18h]
  char v29; // [esp+4BBh] [ebp-11h]

  v29 = -60;
  v28 = 966440225;
  v23 = 1565351951;
  v14 = 0;
  v6 = *(_DWORD *)(a1 + *(_DWORD *)(a1 + 60) + 120);
  do
  {
    v17 = v14;
    v10 = v28 - 966440225;
    v13 = v14;
    do
    {
      v24 = (v13 & (v28 ^ 0x399AB520)) == v28 - 966440225;
      v22 = 48;
      v4 = (v13 >> (v28 - 32)) ^ 0xEDB88320;
      if ( v24 )
        v4 = v13 >> (v28 - 32);
      v10 += 966440226 - v28;
      v13 = v4;
    }
    while ( v10 != 8 );
LABEL_2:
    v2 = v28 ^ 0x399AB421;
    v20[v17] = v4;
    v14 = v17 + 1;
  }
  while ( v17 + 1 != v2 );
  v7 = v6 + a1;
  v12 = *(_DWORD *)(v6 + a1 + 32) + a1;
  v25 = *(_DWORD *)(v6 + a1 + 24);
  if ( !v25 )
    return 0;
  v11 = (unsigned __int16 *)(*(_DWORD *)(v7 + 36) + a1);
  v26 = 0;
  while ( 1 )
  {
    v18 = *(_DWORD *)(v12 + 4 * v26) + a1;
    v16 = 0;
    do
    {
      v8 = v16;
      v5 = *(_BYTE *)(v18 + v16);
      v16 += 966440226 - v28;
    }
    while ( v5 != -60 - v29 );
    v15 = 0;
    if ( v8 )
    {
      v19 = 0;
      v9 = -1;
      do
      {
        v27 = v20[*(unsigned __int8 *)(v18 + v19) ^ (unsigned __int8)v9] ^ (v9 >> 8);
        v19 += v28 ^ 0x399AB520;
        v9 = v27;
      }
      while ( v19 != v8 );
      v15 = v27 ^ (966440224 - v28);
    }
    if ( v15 == a2 )
      return *(_DWORD *)(*(_DWORD *)(v7 + 28) + a1 + 4 * *v11) + a1;
    if ( v23 < 0x351D6412 )
      goto LABEL_2;
    ++v11;
    v26 += 966440226 - v28;
    if ( v26 >= v25 )
      return 0;
  }
}
Evaluated model output (what the LLM said about the code) · op13/result_OpenAI1.txt
## 1. Functionality

### Observed facts from the code

This function takes two arguments:

```c
int __cdecl sub_10001561(int a1, int a2)
```

Likely meaning:

- `a1` = base address of a loaded PE module, e.g. an `HMODULE`
- `a2` = target hash value of an exported function name

The function performs the following steps:

1. Builds a 256-entry CRC lookup table using the polynomial:

```c
0xEDB88320
```

2. Parses the PE export directory of the module at `a1`.

Key PE export fields accessed:

```c
a1 + *(DWORD *)(a1 + 0x3C) + 0x78   // Export Directory RVA
ExportDirectory + 0x18              // NumberOfNames
ExportDirectory + 0x20              // AddressOfNames
ExportDirectory + 0x24              // AddressOfNameOrdinals
ExportDirectory + 0x1C              // AddressOfFunctions
```

3. Iterates through each exported function name.

4. Calculates a CRC32-style hash of the export name.

5. Compares the computed hash against `a2`.

6. If a match is found, resolves the corresponding function address using the export ordinal and returns it.

7. If no match is found, returns `0`.

### High-level pseudocode

```c
void *resolve_export_by_crc32(void *module_base, uint32_t target_hash)
{
    uint32_t crc_table[256];

    build_crc32_table(crc_table, 0xEDB88320);

    IMAGE_EXPORT_DIRECTORY *exp = get_export_directory(module_base);
    if (!exp->NumberOfNames)
        return NULL;

    DWORD *names = module_base + exp->AddressOfNames;
    WORD *ordinals = module_base + exp->AddressOfNameOrdinals;
    DWORD *functions = module_base + exp->AddressOfFunctions;

    for (int i = 0; i < exp->NumberOfNames; i++)
    {
        char *name = module_base + names[i];

        uint32_t hash = crc32(name);

        if (hash == target_hash)
        {
            WORD ordinal = ordinals[i];
            return module_base + functions[ordinal];
        }
    }

    return NULL;
}
```

### Inferred behavior

This is most likely a dynamic API resolver. Malware commonly uses this technique to avoid storing API names directly in the import table. Instead of calling APIs by name, it stores or computes hashes of API names and resolves them at runtime.

For example, instead of importing:

```c
CreateFileA
VirtualAlloc
WinExec
URLDownloadToFileA
```

the malware may store only CRC32 hashes of those names and call this function to resolve the real address at runtime.

---

## 2. Well-known algorithms used

### CRC32

The function implements CRC32 table generation and CRC32 hashing.

Evidence:

```c
0xEDB88320
```

This is the reversed polynomial used by standard CRC-32, also known as IEEE 802.3 CRC32.

Observed CRC32 behavior:

```c
v9 = -1;                        // Initial CRC = 0xFFFFFFFF
v27 = table[byte ^ crc] ^ crc >> 8;
v15 = v27 ^ 0xFFFFFFFF;         // Final XOR
```

So the algorithm is standard CRC32 with:

| Property | Value |
|---|---|
| Polynomial | `0xEDB88320` |
| Initial value | `0xFFFFFFFF` |
| Final XOR | `0xFFFFFFFF` |
| Input | Exported function name string |
| Purpose | API name hashing |

---

## 3. Indicators of Compromise

No traditional IOCs are directly present in this snippet.

### File paths

None observed.

### IP addresses / domains

None observed.

### Registry keys

None observed.

### Commands or scripts

None observed.

### Other useful indicators

These are not network/file/registry IOCs, but are useful static-analysis indicators:

| Indicator | Type | Description |
|---|---|---|
| `0xEDB88320` | Crypto/hash constant | CRC32 reversed polynomial |
| `0xFFFFFFFF` | CRC32 constant | Initial/final XOR value |
| PE export parsing offsets | Behavior | Manual export table walking |
| API hashing | Behavior | Export names are hashed rather than referenced directly |

---

## 4. MITRE ATT&CK mapping

### T1027.007 — Obfuscated Files or Information: Dynamic API Resolution

**Observed behavior:**

The code manually walks the PE export table and resolves a function address by comparing a CRC32 hash of each export name against a supplied hash.

Evidence from code:

```c
v6 = *(DWORD *)(a1 + *(DWORD *)(a1 + 60) + 120);   // Export Directory RVA
v12 = *(DWORD *)(v6 + a1 + 32) + a1;               // AddressOfNames
v11 = (WORD *)(*(DWORD *)(v7 + 36) + a1);          // AddressOfNameOrdinals
...
if (v15 == a2)
    return *(DWORD *)(*(DWORD *)(v7 + 28) + a1 + 4 * *v11) + a1;
```

**Justification:**

The function avoids direct imports by resolving APIs dynamically using hashed names. This is a common malware obfuscation method used to hinder static analysis and signature-based detection.

---

### T1027 — Obfuscated Files or Information

**Observed behavior:**

The code uses extensive arithmetic obfuscation, opaque constants, and confusing control-flow constructs.

Examples:

```c
v28 = 966440225;                  // 0x399AB521
v28 ^ 0x399AB520                  // evaluates to 1
v28 ^ 0x399AB421                  // evaluates to 256
966440226 - v28                   // evaluates to 1
966440224 - v28                   // evaluates to -1 / 0xFFFFFFFF
v29 = -60;
-60 - v29                         // evaluates to 0
```

There is also an effectively dead or opaque branch:

```c
v23 = 1565351951;
...
if (v23 < 0x351D6412)
    goto LABEL_2;
```

`v23` is greater than `0x351D6412`, so this branch is never taken under normal execution.

**Justification:**

The constants and control flow are intentionally written in a misleading way to obscure simple operations such as incrementing by 1, comparing against zero, and building a 256-entry table.

---

### T1106 — Native API

**Inferred behavior, not directly observed in this snippet.**

This function resolves Windows API addresses from a module’s export table. The snippet itself does not call the resolved API, but its return value is almost certainly intended to be used as a function pointer by other code.

Evidence:

```c
return function_address;
```

**Justification:**

Malware often dynamically resolves Windows APIs and then invokes them through function pointers. However, this specific function only performs resolution; actual API invocation is not shown in the provided snippet.

---

## 5. Obfuscation and evasion techniques

### Dynamic API resolution by hash

**Observed.**

The function does not reference API names directly. Instead, it hashes export names and compares them against a supplied hash value.

This helps evade:

- Static import-table analysis
- YARA rules matching imported APIs
- Basic string scanning for suspicious API names

---

### CRC32 API hashing

**Observed.**

The resolver uses CRC32 to hash export names.

Evidence:

```c
0xEDB88320
```

and the CRC update operation:

```c
crc = table[(byte ^ crc) & 0xFF] ^ (crc >> 8);
```

This is a common malware technique for hiding API names.

---

### Arithmetic constant obfuscation

**Observed.**

Many simple values are hidden behind arithmetic or XOR operations.

Examples:

```c
v28 = 966440225;              // 0x399AB521

v28 ^ 0x399AB520 == 1
v28 ^ 0x399AB421 == 256
966440226 - v28 == 1
966440224 - v28 == 0xFFFFFFFF
```

This obscures obvious constants such as:

- `1`
- `256`
- `0`
- `0xFFFFFFFF`

---

### Opaque predicate / dead branch

**Observed.**

The code contains a branch that appears unreachable:

```c
v23 = 1565351951;

if (v23 < 0x351D6412)
    goto LABEL_2;
```

Since `1565351951` is greater than `0x351D6412`, this condition is false. This appears to be an opaque predicate or decompiler-confusing construct.

---

### Decompiler-confusing constructs

**Observed.**

Example:

```c
v13 >> (v28 - 32)
```

At first glance, this appears invalid or nonsensical because `v28 - 32` is a very large number. On x86, however, shift counts are masked, so this effectively becomes a shift by `1`.

This kind of construct can confuse static analysis and make the generated pseudocode harder to read.

---

## 6. Observed facts vs inferred behavior

### Observed facts

- The function builds a CRC32 lookup table.
- The CRC32 polynomial is `0xEDB88320`.
- The function parses the PE export directory of a module.
- It iterates over exported function names.
- It computes a CRC32 hash for each export name.
- It compares that hash to the input parameter `a2`.
- It returns the resolved function address when a matching hash is found.
- It returns `0` if no matching export is found.
- It contains arithmetic obfuscation and an apparently unreachable branch.

### Inferred behavior

- `a1` is likely an `HMODULE` or PE image base.
- `a2` is likely a precomputed CRC32 hash of a Windows API name.
- The function is likely used by malware as a dynamic API resolver.
- The broader malware likely avoids suspicious imports by resolving APIs at runtime.
- Other parts of the malware likely call the returned function pointer, but that behavior is not shown in this snippet.

LLM judge panel

ClaudeAI judge verdict: satisfiedop13/judge_ClaudeAI_OpenAI_up0_1.txt
{
  "understanding_point": "CRC32 hashing",
  "full_evaluation": "The understanding point is simply 'CRC32 hashing'. The summary repeatedly and explicitly states that the function implements CRC32 table generation and CRC32 hashing. It identifies the polynomial 0xEDB88320 as the standard reversed CRC-32 polynomial, describes the initial value 0xFFFFFFFF, the final XOR 0xFFFFFFFF, and the CRC update operation crc = table[(byte ^ crc) & 0xFF] ^ (crc >> 8). It clearly states the function computes a CRC32 hash of each export name. This fully and clearly expresses the use of CRC32 hashing.",
  "explanation": "The summary explicitly and thoroughly states that the function implements CRC32 hashing, including the polynomial, init/final XOR values, and the CRC update operation.",
  "evidence": "The function implements CRC32 table generation and CRC32 hashing.",
  "support_strength": 3,
  "satisfied": "true"
}
GeminiAI judge verdict: satisfiedop13/judge_GeminiAI_OpenAI_up0_1.txt
{
  "understanding_point": "CRC32 hashing",
  "full_evaluation": "The summary explicitly states that the function implements \"CRC32 hashing\" multiple times. It details how the function calculates a \"CRC32-style hash of the export name\" and uses \"CRC32 API hashing\" as an obfuscation technique. It also provides details about the CRC32 algorithm used, including the polynomial, initial value, and final XOR.",
  "explanation": "The summary explicitly states that the function implements CRC32 hashing and describes its purpose and characteristics in detail.",
  "evidence": "The function implements CRC32 table generation and CRC32 hashing.",
  "support_strength": 3,
  "satisfied": "true"
}
OpenAI judge verdict: satisfiedop13/judge_OpenAI_OpenAI_up0_1.txt
{
  "understanding_point": "CRC32 hashing",
  "full_evaluation": "The candidate summary clearly and repeatedly states that the code performs CRC32 hashing. It says the function builds a CRC lookup table with polynomial 0xEDB88320, calculates a CRC32-style hash of exported function names, compares computed hashes against an input target hash, and specifically identifies the algorithm as standard CRC32 with initial value 0xFFFFFFFF and final XOR 0xFFFFFFFF. There are no contradictions. This directly satisfies the understanding point \"CRC32 hashing.\"",
  "explanation": "The summary explicitly identifies CRC32 hashing as the algorithm used and describes its use for hashing exported function names. It also provides supporting CRC32 constants and update behavior.",
  "evidence": "The function implements CRC32 table generation and CRC32 hashing.",
  "support_strength": 3,
  "satisfied": "true"
}

Your verdict