Reverse Engineering Techniques • Windows

Deconstructing Dynamic API Resolution: Locating NTDLL and Rebuilding IATs

Walk the Windows PEB to locate NTDLL in memory, parse Export Address Tables, and dynamically reconstruct Import Address Tables without static imports.

PART-1: https://github.com/Lynk4/mare/blob/main/Malware%20Analysis/Windows/Reversing%20Hash-Based%20API%20Resolution/README.md

Now we begin Part - 2

▪Analyze code that locates the image base of NTDLL
▪Demonstrate how to dynamically explore related structures
▪Begin to understand how an import table is dynamically constructed

Sample used:

IDA Analysis

start

The binary starts at:

CPP
.text:00404EED ; ---------------------------------------------------------------------------
.text:00404EED
.text:00404EED                 public start
.text:00404EED start:
.text:00404EED                 call    sub_404D53
.text:00404EF2                 push    0
.text:00404EF4                 push    dword_4050E4
.text:00404EFA                 pop     eax
.text:00404EFB                 call    eax
.text:00404EFB ; ---------------------------------------------------------------------------
.text:00404EFD                 db 3 dup(0)
Screenshot 2026-05-29 at 3.12.27 PM.png
Figure: Screenshot 2026-05-29 at 3.12.27 PM.png Click to zoom ↗

We have an indirect call to eax and we don’t know what’s is in eax.

sub404D53

Navigate into sub_404D53 .

Inside this function we have identified the same problem, making indirect call throughout the function.

We have isolated our analysis down to two function: sub_401728 and sub_40175E .

CPP
.text:00404D61                 call    sub_401728
.text:00404D75                 call    sub_40175E
Screenshot 2026-05-29 at 3.20.36 PM.png
Figure: Screenshot 2026-05-29 at 3.20.36 PM.png Click to zoom ↗

sub401728

We will continue our analysis for this function to better understand how this function gets the base of a dll.

we already explored this function.

how it’s creating the checksum value ensuring that all ascii characters are lowered case and then comparing that checksum to the pre-computed value

that was passed in. We didn’t explored what happend after the comparison.

Screenshot 2026-05-29 at 3.27.52 PM.png
Figure: Screenshot 2026-05-29 at 3.27.52 PM.png Click to zoom ↗

The last analysis we did in this function is to verofy when we move into esi , [edi+28h] hex we have a pointer. not an ascii strings but actually a unicode string.

CPP
loc_401738:
mov     esi, [edi+28h]
xor     edx, edx

and that actually makes a little sense. If you notice in the block that follows were loading a string word not a string byte. It’s that instruction that is counting for the unicode value. However none of the character is going to user both the bytes that’s why we are only using the al register. The lower 8 bits of that value.

CPP
loc_40173D:
lodsw
test    al, al
jz      short loc_401754
Screenshot 2026-05-29 at 3.43.28 PM.png
Figure: Screenshot 2026-05-29 at 3.43.28 PM.png Click to zoom ↗

In the slide previous we have also looked at the code and the associated structure starting with the PEB . And navigating to the final structure that allows us to not only walk to the linked list of the loaded modules but then also ultimately get the image base.

These instructions begins at the address: 0040172B .

CPP
.text:00401729                 xor     edi, edi
.text:0040172B                 mov     edi, large fs:30h
.text:00401732                 mov     edi, [edi+0Ch]
.text:00401735                 mov     edi, [edi+14h]
Screenshot 2026-05-29 at 3.47.12 PM.png
Figure: Screenshot 2026-05-29 at 3.47.12 PM.png Click to zoom ↗

Now we can switch to a debugger and step through them dynamically.

Windbg

load the binary in windbg

Set breakpoint at 0040172B .

CPP
bp 0040172B
Screenshot 2026-05-29 at 3.56.16 PM.png
Figure: Screenshot 2026-05-29 at 3.56.16 PM.png Click to zoom ↗

Hit the breakpoint: 0040172B

Screenshot 2026-05-29 at 3.57.00 PM.png
Figure: Screenshot 2026-05-29 at 3.57.00 PM.png Click to zoom ↗

We stopped at the PEB structure. Remember when we reach this breakpoint the instructions has not been executed yet. We have step beyond it to get the pointer into edi. so step over.

The pointer to our PEB is now in the edi register as 002C1000 . We can use the dt command as well as the symbol for the PEB.

We can use the dt command to explore the structure. and if we provide the address as an additional argument. It will actually map the value in the memory.

CPP
0:000> dt _peb 002C1000
ntdll!_PEB
   +0x000 InheritedAddressSpace : 0 ''
   +0x001 ReadImageFileExecOptions : 0 ''
   +0x002 BeingDebugged    : 0x1 ''
   +0x003 BitField         : 0 ''
   +0x003 ImageUsesLargePages : 0y0
   +0x003 IsProtectedProcess : 0y0
   +0x003 IsImageDynamicallyRelocated : 0y0
   +0x003 SkipPatchingUser32Forwarders : 0y0
   +0x003 IsPackagedProcess : 0y0
   +0x003 IsAppContainer   : 0y0
   +0x003 IsProtectedProcessLight : 0y0
   +0x003 IsLongPathAwareProcess : 0y0
   +0x004 Mutant           : 0xffffffff Void
   +0x008 ImageBaseAddress : 0x00400000 Void
   +0x00c Ldr              : 0x772a5d80 _PEB_LDR_DATA
   +0x010 ProcessParameters : 0x006b22a0 _RTL_USER_PROCESS_PARAMETERS
   +0x014 SubSystemData    : (null) 
   +0x018 ProcessHeap      : 0x006b0000 Void
   +0x01c FastPebLock      : 0x772a5b40 _RTL_CRITICAL_SECTION
   +0x020 AtlThunkSListPtr : (null) 
   +0x024 IFEOKey          : (null) 
   +0x028 CrossProcessFlags : 0
   +0x028 ProcessInJob     : 0y0
   +0x028 ProcessInitializing : 0y0
   +0x028 ProcessUsingVEH  : 0y0
   +0x028 ProcessUsingVCH  : 0y0
   +0x028 ProcessUsingFTH  : 0y0
   +0x028 ProcessPreviouslyThrottled : 0y0
   +0x028 ProcessCurrentlyThrottled : 0y0
   +0x028 ProcessImagesHotPatched : 0y0
   +0x028 ReservedBits0    : 0y000000000000000000000000 (0)
   +0x02c KernelCallbackTable : (null) 
   +0x02c UserSharedInfoPtr : (null) 
   +0x030 SystemReserved   : 0
   +0x034 AtlThunkSListPtr32 : (null) 
   +0x038 ApiSetMap        : 0x00040000 Void
   +0x03c TlsExpansionCounter : 0
   +0x040 TlsBitmap        : 0x772a5d30 Void
   +0x044 TlsBitmapBits    : [2] 0x10001
   +0x04c ReadOnlySharedMemoryBase : 0x7fe50000 Void
   +0x050 SharedData       : (null) 
   +0x054 ReadOnlyStaticServerData : 0x7fe50750  -> (null) 
   +0x058 AnsiCodePageData : 0x7ffb0000 Void
   +0x05c OemCodePageData  : 0x7ffc0228 Void
   +0x060 UnicodeCaseTableData : 0x7ffd0650 Void
   +0x064 NumberOfProcessors : 2
   +0x068 NtGlobalFlag     : 0x70
   +0x070 CriticalSectionTimeout : _LARGE_INTEGER 0xffffe86d`079b8000
   +0x078 HeapSegmentReserve : 0x100000
   +0x07c HeapSegmentCommit : 0x2000
   +0x080 HeapDeCommitTotalFreeThreshold : 0x10000
   +0x084 HeapDeCommitFreeBlockThreshold : 0x1000
   +0x088 NumberOfHeaps    : 1
   +0x08c MaximumNumberOfHeaps : 0x10
   +0x090 ProcessHeaps     : 0x772a4840  -> 0x006b0000 Void
   +0x094 GdiSharedHandleTable : (null) 
   +0x098 ProcessStarterHelper : (null) 
   +0x09c GdiDCAttributeList : 0
   +0x0a0 LoaderLock       : 0x772a33f8 _RTL_CRITICAL_SECTION
   +0x0a4 OSMajorVersion   : 0xa
   +0x0a8 OSMinorVersion   : 0
   +0x0ac OSBuildNumber    : 0x4a65
   +0x0ae OSCSDVersion     : 0
   +0x0b0 OSPlatformId     : 2
   +0x0b4 ImageSubsystem   : 2
   +0x0b8 ImageSubsystemMajorVersion : 4
   +0x0bc ImageSubsystemMinorVersion : 0
   +0x0c0 ActiveProcessAffinityMask : 3
   +0x0c4 GdiHandleBuffer  : [34] 0
   +0x14c PostProcessInitRoutine : (null) 
   +0x150 TlsExpansionBitmap : 0x772a5d18 Void
   +0x154 TlsExpansionBitmapBits : [32] 1
   +0x1d4 SessionId        : 1
   +0x1d8 AppCompatFlags   : _ULARGE_INTEGER 0x0
   +0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER 0x0
   +0x1e8 pShimData        : 0x001b0000 Void
   +0x1ec AppCompatInfo    : (null) 
   +0x1f0 CSDVersion       : _UNICODE_STRING ""
   +0x1f8 ActivationContextData : (null) 
   +0x1fc ProcessAssemblyStorageMap : (null) 
   +0x200 SystemDefaultActivationContextData : 0x001a0000 _ACTIVATION_CONTEXT_DATA
   +0x204 SystemAssemblyStorageMap : (null) 
   +0x208 MinimumStackCommit : 0
   +0x20c SparePointers    : [4] (null) 
   +0x21c SpareUlongs      : [5] 0
   +0x230 WerRegistrationData : (null) 
   +0x234 WerShipAssertPtr : (null) 
   +0x238 pUnused          : (null) 
   +0x23c pImageHeaderHash : (null) 
   +0x240 TracingFlags     : 0
   +0x240 HeapTracingEnabled : 0y0
   +0x240 CritSecTracingEnabled : 0y0
   +0x240 LibLoaderTracingEnabled : 0y0
   +0x240 SpareTracingBits : 0y00000000000000000000000000000 (0)
   +0x248 CsrServerReadOnlySharedMemoryBase : 0x00007df4`585a0000
   +0x250 TppWorkerpListLock : 0
   +0x254 TppWorkerpList   : _LIST_ENTRY [ 0x8afe80 - 0x8afe80 ]
   +0x25c WaitOnAddressHashTable : [128] (null) 
   +0x45c TelemetryCoverageHeader : (null) 
   +0x460 CloudFileFlags   : 0
   +0x464 CloudFileDiagFlags : 0
   +0x468 PlaceholderCompatibilityMode : 0 ''
   +0x469 PlaceholderCompatibilityModeReserved : [7]  ""
   +0x470 LeapSecondData   : 0x7ffa0000 _LEAP_SECOND_DATA
   +0x474 LeapSecondFlags  : 0
   +0x474 SixtySecondEnabled : 0y0
   +0x474 Reserved         : 0y0000000000000000000000000000000 (0)
   +0x478 NtGlobalFlag2    : 0
Screenshot 2026-05-29 at 4.05.03 PM.png
Figure: Screenshot 2026-05-29 at 4.05.03 PM.png Click to zoom ↗

the next instruction is we are moving into edi , [edi+0Ch] hex .

CPP
00401732 8b7f0c         mov     edi, dword ptr [edi+0Ch]

That means we are accessing the member from the structure. That’s what the pointer to edi is

as an offset of +C . This is a peb loader data structure _PEB_LDR_DATA.

Screenshot 2026-05-29 at 4.12.39 PM.png
Figure: Screenshot 2026-05-29 at 4.12.39 PM.png Click to zoom ↗

Let’s continue execution and explore that structure.

Screenshot 2026-05-29 at 4.41.30 PM.png
Figure: Screenshot 2026-05-29 at 4.41.30 PM.png Click to zoom ↗

We can use the same dt command along with the _peb_ldr_data structure in order explore the member’s of that structure.

CPP
0:000> dt _peb_ldr_data 772A5D80
ntdll!_PEB_LDR_DATA
   +0x000 Length           : 0x30
   +0x004 Initialized      : 0x1 ''
   +0x008 SsHandle         : (null) 
   **+0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x6b41a8 - 0x6b4958 ]
   +0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x6b41b0 - 0x6b4960 ]
   +0x01c InInitializationOrderModuleList : _LIST_ENTRY [ 0x6b40b0 - 0x6b4598 ]**
   +0x024 EntryInProgress  : (null) 
   +0x028 ShutdownInProgress : 0 ''
   +0x02c ShutdownThreadId : (null) 

Here we can see the three doubly-linked list.

List NameOffset in _PEB_LDR_DATAOrder of ModulesMost Commonly Used by Malware?Why Malware Prefers It
InLoadOrderModuleList+0x00CIn the order they were loadedSometimesEasy to understand but more visible
InMemoryOrderModuleList+0x014In the order they appear in memoryYes (Most Popular)kernel32.dll appears very early
InInitializationOrderModuleList+0x01CIn the order their DllMain was calledVery CommonAlso has kernel32.dll early, slightly cleaner
Screenshot 2026-05-29 at 4.42.44 PM.png
Figure: Screenshot 2026-05-29 at 4.42.44 PM.png Click to zoom ↗

Next the code is going to move into edi, [edi+14h] hex. So this actually our InMemoryOrderModuleList .

This is a entry list item. It’s a doubly-linked list that contains forward and backward links.

Screenshot 2026-05-29 at 4.49.26 PM.png
Figure: Screenshot 2026-05-29 at 4.49.26 PM.png Click to zoom ↗

This value:0x6b41b0 will point to the next structure.

CPP
   +0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x6b41b0 - 0x6b4960 ]

The structure loader data table entry.

use dt command with the address from the providing link. We can see actual value map to the structure.

CPP
0:000> dt _ldr_data_table_entry 0x6b41b0
ntdll!_LDR_DATA_TABLE_ENTRY
   +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x6b40a8 - 0x772a5d94 ]
   +0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x400000 - 0x404eed ]
   +0x018 DllBase          : 0x00006000 Void
   +0x01c EntryPoint       : 0x00480046 Void
   +0x020 SizeOfImage      : 0x6b2768
   +0x024 FullDllName      : _UNICODE_STRING "sample.exe"
   +0x02c BaseDllName      : _UNICODE_STRING "--- memory read error at address 0x0000ffff ---"
   +0x034 FlagGroup        : [4]  "???"
   +0x034 Flags            : 0x772a5bf0
   +0x034 PackagedBinary   : 0y0
   +0x034 MarkedForRemoval : 0y0
   +0x034 ImageDll         : 0y0
   +0x034 LoadNotificationsSent : 0y0
   +0x034 TelemetryEntryProcessed : 0y1
   +0x034 ProcessStaticImport : 0y1
   +0x034 InLegacyLists    : 0y1
   +0x034 InIndexes        : 0y1
   +0x034 ShimDll          : 0y1
   +0x034 InExceptionTable : 0y1
   +0x034 ReservedFlags1   : 0y10
   +0x034 LoadInProgress   : 0y1
   +0x034 LoadConfigProcessed : 0y0
   +0x034 EntryProcessed   : 0y1
   +0x034 ProtectDelayLoad : 0y0
   +0x034 ReservedFlags3   : 0y10
   +0x034 DontCallForThreads : 0y0
   +0x034 ProcessAttachCalled : 0y1
   +0x034 ProcessAttachFailed : 0y0
   +0x034 CorDeferredValidate : 0y1
   +0x034 CorImage         : 0y0
   +0x034 DontRelocate     : 0y0
   +0x034 CorILOnly        : 0y1
   +0x034 ChpeImage        : 0y1
   +0x034 ReservedFlags5   : 0y01
   +0x034 Redirected       : 0y1
   +0x034 ReservedFlags6   : 0y11
   +0x034 CompatDatabaseProcessed : 0y0
   +0x038 ObsoleteLoadCount : 0x5bf0
   +0x03a TlsIndex         : 0x772a
   +0x03c HashLinks        : _LIST_ENTRY [ 0x57634955 - 0x0 ]
   +0x044 TimeDateStamp    : 0
   +0x048 EntryPointActivationContext : 0x006b4268 _ACTIVATION_CONTEXT
   +0x04c Lock             : 0x006b4268 Void
   +0x050 DdagNode         : 0x006b4268 _LDR_DDAG_NODE
   +0x054 NodeModuleLink   : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x05c LoadContext      : 0x771810b4 _LDRP_LOAD_CONTEXT
   +0x060 ParentDllBase    : (null) 
   +0x064 SwitchBackContext : 0x006b49c0 Void
   +0x068 BaseAddressIndexNode : _RTL_BALANCED_NODE
   +0x074 MappingInfoIndexNode : _RTL_BALANCED_NODE
   +0x080 OriginalBase     : 0x69224a28
   +0x088 LoadTime         : _LARGE_INTEGER 0x00000004`74d5776e
   +0x090 BaseNameHashValue : 0
   +0x094 LoadReason       : 2 ( LoadReasonDynamicForwarderDependency )
   +0x098 ImplicitPathOptions : 0
   +0x09c ReferenceCount   : 0
   +0x0a0 DependentLoadFlags : 0xabababab
   +0x0a4 SigningLevel     : 0xab ''
Screenshot 2026-05-29 at 4.57.08 PM.png
Figure: Screenshot 2026-05-29 at 4.57.08 PM.png Click to zoom ↗

For example the FullDllName is sample.exe which is the name i gave to this executable.

CPP
   +0x024 FullDllName      : _UNICODE_STRING "sample.exe"

The order in which we will access both the executable and dll’s will depend based of the doubly-linked list used.

If you look at the member underneath FullDllName is BaseDllName. It looks like there’s a memory read error.

CPP
   +0x02c BaseDllName      : _UNICODE_STRING "--- memory read error at address 0x0000ffff ---"
Screenshot 2026-05-29 at 5.05.47 PM.png
Figure: Screenshot 2026-05-29 at 5.05.47 PM.png Click to zoom ↗

Remember that these doubly linked-list are 8 byte structure within the loader data table entry.

The forward link point’s to the appropriate, to the corresponding forward links in each additional structure.

That means InorderMemory links were actually 8 bytes already into the structure. We can see that in the structure definition.

CPP
0:000> dt _ldr_data_table_entry 0x6b41b0
ntdll!_LDR_DATA_TABLE_ENTRY
   +**0x000** InLoadOrderLinks : _LIST_ENTRY [ 0x6b40a8 - 0x772a5d94 ]
   +**0x008** InMemoryOrderLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
   +**0x010** InInitializationOrderLinks : _LIST_ENTRY [ 0x400000 - 0x404eed ]
   +**0x018** DllBase          : 0x00006000 Void
▪InLoadOrderLinks at offset of 0 and 4
▪InMemoryOrderLinks at offset of 8 and 0xC

That means we look at the DLL name or we want to map the content of the structure in the memory. We have to account for that 8 byte offset.

What this amount for us is to subtract 8 bytes from that original address Once we do that and dumped that structure.

CPP
0:000> dt _ldr_data_table_entry [6b41b0-8]
CPP
0:000> dt _ldr_data_table_entry [6b41b0-8]
ntdll!_LDR_DATA_TABLE_ENTRY
   +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x6b40a0 - 0x772a5d8c ]
   +0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x6b40a8 - 0x772a5d94 ]
   +0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x018 DllBase          : 0x00400000 Void
   +0x01c EntryPoint       : 0x00404eed Void
   +0x020 SizeOfImage      : 0x6000
   +0x024 FullDllName      : _UNICODE_STRING "C:\Users\redteam\Desktop\sample.exe"
   +0x02c BaseDllName      : _UNICODE_STRING "sample.exe"
   +0x034 FlagGroup        : [4]  "???"
   +0x034 Flags            : 0x800022cc
   +0x034 PackagedBinary   : 0y0
   +0x034 MarkedForRemoval : 0y0
   +0x034 ImageDll         : 0y1
   +0x034 LoadNotificationsSent : 0y1
   +0x034 TelemetryEntryProcessed : 0y0
   +0x034 ProcessStaticImport : 0y0
   +0x034 InLegacyLists    : 0y1
   +0x034 InIndexes        : 0y1
   +0x034 ShimDll          : 0y0
   +0x034 InExceptionTable : 0y1
   +0x034 ReservedFlags1   : 0y00
   +0x034 LoadInProgress   : 0y0
   +0x034 LoadConfigProcessed : 0y1
   +0x034 EntryProcessed   : 0y0
   +0x034 ProtectDelayLoad : 0y0
   +0x034 ReservedFlags3   : 0y00
   +0x034 DontCallForThreads : 0y0
   +0x034 ProcessAttachCalled : 0y0
   +0x034 ProcessAttachFailed : 0y0
   +0x034 CorDeferredValidate : 0y0
   +0x034 CorImage         : 0y0
   +0x034 DontRelocate     : 0y0
   +0x034 CorILOnly        : 0y0
   +0x034 ChpeImage        : 0y0
   +0x034 ReservedFlags5   : 0y00
   +0x034 Redirected       : 0y0
   +0x034 ReservedFlags6   : 0y00
   +0x034 CompatDatabaseProcessed : 0y1
   +0x038 ObsoleteLoadCount : 0xffff
   +0x03a TlsIndex         : 0
   +0x03c HashLinks        : _LIST_ENTRY [ 0x772a5bf0 - 0x772a5bf0 ]
   +0x044 TimeDateStamp    : 0x57634955
   +0x048 EntryPointActivationContext : (null) 
   +0x04c Lock             : (null) 
   +0x050 DdagNode         : 0x006b4268 _LDR_DDAG_NODE
   +0x054 NodeModuleLink   : _LIST_ENTRY [ 0x6b4268 - 0x6b4268 ]
   +0x05c LoadContext      : (null) 
   +0x060 ParentDllBase    : (null) 
   +0x064 SwitchBackContext : 0x771810b4 Void
   +0x068 BaseAddressIndexNode : _RTL_BALANCED_NODE
   +0x074 MappingInfoIndexNode : _RTL_BALANCED_NODE
   +0x080 OriginalBase     : 0x400000
   +0x088 LoadTime         : _LARGE_INTEGER 0x01dcef55`69224a28
   +0x090 BaseNameHashValue : 0x74d5776e
   +0x094 LoadReason       : 4 ( LoadReasonDynamicLoad )
   +0x098 ImplicitPathOptions : 0
   +0x09c ReferenceCount   : 2
   +0x0a0 DependentLoadFlags : 0
   +0x0a4 SigningLevel     : 0 ''

Every thing lines up. Not only we have a valid value’s for both the full dll name, base dll name but now all other value’s will be correct.

Screenshot 2026-05-29 at 5.24.11 PM.png
Figure: Screenshot 2026-05-29 at 5.24.11 PM.png Click to zoom ↗

By the end of this instruction mov edi, dword ptr [edi+14h] we know this is pointing to the loader data table entry structure. we are going to use that structure again.

CPP
00401735 8b7f14         mov     edi, dword ptr [edi+14h]

So keep in mind that we were at a offset based of the doubly-linked list that we are using.

Our next instruction

CPP
00401738 8b7728         mov     esi, dword ptr [edi+28h]

Let’s step to this instruction and investigate further.

Screenshot 2026-05-29 at 5.30.24 PM.png
Figure: Screenshot 2026-05-29 at 5.30.24 PM.png Click to zoom ↗

This instruction also takes an account of the offset That we have been discussing.

This function needs a pointer to the name of the dll. which actually is in esi now. But how did it get that from an offset of 28h hex. If we see the structure of loader data table entry There’s no offset.

If we are at a offset of 8 we simple need to add 8 to 28h hex . we get 0x30 .

CPP
0x28 + 0x8 = 0x30

And again there’s no offset of hex 30 in the loader data table entry. the closest one will be +0x02c

CPP
   +0x02c BaseDllName      : _UNICODE_STRING "sample.exe"

Which is a BaseDllName and actually maes sense what we are trying to obtian.

If you notice this is a unicode string. .This is in fact a another structure.

The first 4 bytes of the structure defines the length and maximum length of the string.

The last 4 bytes are pointer to the strings itself. Which is why this code is accessing a offset of +0x30 hex.

We can confirm this by dumping a value of esi:

CPP
0:000> du esi
006b279a  "sample.exe"
Screenshot 2026-05-29 at 5.42.55 PM.png
Figure: Screenshot 2026-05-29 at 5.42.55 PM.png Click to zoom ↗

And we actually do have a pointer to the name of the dll or executable.

The last item we need to discuss is what happens after the comparison.

We move into eax, [edi+10h] .

Recall the edi is a pointer to our loader data table entry item. So we accessing a member at a offset of +0x10 hex.

Screenshot 2026-05-29 at 5.45.05 PM.png
Figure: Screenshot 2026-05-29 at 5.45.05 PM.png Click to zoom ↗

If we take a account of fact that we are already 8 bytes into the structure. That gives us the offset of +0x18 hex and it’s DllBase. This value is return in eax.

CPP
   +0x018 DllBase          : 0x00400000 Void
Screenshot 2026-05-29 at 5.49.18 PM.png
Figure: Screenshot 2026-05-29 at 5.49.18 PM.png Click to zoom ↗

That set’s the stage for the last function we are going to analyze. Our call to sub_40175E .

Screenshot 2026-05-29 at 5.53.25 PM.png
Figure: Screenshot 2026-05-29 at 5.53.25 PM.png Click to zoom ↗
Copied