Finding load address of 32 bit NtDll.dll from 64 bit parent on WOW64

2,116 views
Skip to first unread message

Kris Warkentin

unread,
Sep 25, 2013, 9:04:23 AM9/25/13
to dynamor...@googlegroups.com
This is not DR related but rather in my own code but you guys seem to really know what you're doing so I'm hoping you might be willing to help me out.

I'm struggling to do something that I feel should be very easy.

I've spawned a 32 bit child suspended from a 64 bit parent and am doing some manipulation of it from the parent. It's very early so only the wow64 and nt dlls are present.

I'm hooking all the 64 bit ntdll functions but I also need to do some work in the 32 bit layer so I'm trying to figure out from the parent code what the base address of the childs 32 bit ntdll is.

Windbg and process explorer both show the base load address of all the dlls at this point so clearly the information exists but I'm unable to figure out how to get the address of the 32 bit ntdll.

I feel like this code SHOULD do what I'm attempting. Just POC so not the cleanest but here's what I'm trying.

#define TEB32OFFSET 0x2000

void interceptNtDll32(HANDLE hProcess)
{
    THREAD_BASIC_INFORMATION tbi;
    NTSTATUS ntrv;
    TEB32 teb32;
    void *teb32addr;
    PEB_LDR_DATA32 ldrData;
    PEB32 peb32;
    LIST_ENTRY32 *pMark = NULL;
    LDR_DATA_TABLE_ENTRY32 ldrDataTblEntry;
    size_t bytes_read;
    HANDLE hThread = getThreadHandle(hProcess);
 
    /* Used to be able to get 32 bit PEB from PEB64 with 0x1000 offset but
       Windows 8 changed that so we do it indirectly from the TEB */
    if(!hThread)
        return;

    /* Get thread basic information to get 64 bit TEB */
    ntrv = NtQueryInformationThread(hThread, ThreadBasicInformation, &tbi, sizeof(tbi), NULL);
    if(ntrv != 0){
        goto out;
    }

    /* Use magic to find 32 bit TEB */
    teb32addr = (char *)tbi.TebBaseAddress + TEB32OFFSET; // Magic...
    ntrv = NtReadVirtualMemory(hProcess, teb32addr, &teb32, sizeof(teb32), NULL);
    if(ntrv != 0 || teb32.NtTib.Self != (DWORD)teb32addr){  // Verify magic...
        goto out;
    }

    /* TEB32 has address for 32 bit PEB.*/
    ntrv = NtReadVirtualMemory(hProcess, (void *)teb32.ProcessEnvironmentBlock, &peb32, sizeof(peb32), NULL);
    if(ntrv != 0){
        goto out;
    }

    /* This is where it goes south. The 32 bit PEB LOOKS like it should be okay but Ldr is NULL
       so we don't get the 32 bit ldr information. */
    ntrv = NtReadVirtualMemory(hProcess, (void *)peb32.Ldr, &ldrData, sizeof(ldrData), &bytes_read);
    if(ntrv != 0){
        goto out;
    }

    /* If the above had worked we could now iterate through the ldr data to find ntdll32.dll */
    ntrv = NtReadVirtualMemory(hProcess, (VOID *)ldrData.InLoadOrderModuleList.Flink, &ldrDataTblEntry, sizeof(ldrDataTblEntry), NULL);
...

Any suggestions of alternate ways of doing it? Running through the 64 bit ldr data only gives me the wow64 and 64 bit ntdll addresses.

cheers,

Kris

Derek Bruening

unread,
Sep 25, 2013, 6:00:03 PM9/25/13
to dynamor...@googlegroups.com
You could walk the child's address space and examine each MEM_IMAGE until you find ntdll32.

- Derek


--
You received this message because you are subscribed to the Google Groups "DynamoRIO Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dynamorio-use...@googlegroups.com.
To post to this group, send email to dynamor...@googlegroups.com.
Visit this group at http://groups.google.com/group/dynamorio-users.
For more options, visit https://groups.google.com/groups/opt_out.

Kris Warkentin

unread,
Sep 25, 2013, 7:07:24 PM9/25/13
to dynamor...@googlegroups.com
Interesting. I had thought about doing something like that. I had seen something similar done in Linux to find the kernel call table (which isn't an exported symbol). Seems very inelegant though. The fact that windbg and process explorer can see the address at that point implies there must be a nice way to do it. Looking at the PEB32, it seems like it's just not initiated at that point. Unless there's a special one for WOW and I've got the wrong one.

Thanks for the help. If you happen to think of something else, I'd love to hear it. Looking at the DR open issues, it seems like you guys have some TODO items with cross architecture stuff too. WOW64 is such a pain.

cheers,

Kris

Kris Warkentin

unread,
Sep 25, 2013, 7:44:29 PM9/25/13
to dynamor...@googlegroups.com
Hmm...I see what you're saying about MEM_IMAGE. I hadn't heard of VirtualQueryEx before. It looks like it might make it fairly easy to scan through the childs address space.

The only awkward bit is that the 64 bit kernel32.dll is hidden when you're in a WOW64 process so I will have to unhide it and look up the function. I think that should be okay as long as I don't have to relocate it as well.

Thanks for the suggestion.

cheers,

Kris

Derek Bruening

unread,
Sep 25, 2013, 11:15:27 PM9/25/13
to dynamor...@googlegroups.com
On Wed, Sep 25, 2013 at 7:07 PM, Kris Warkentin <kewa...@gmail.com> wrote:
Interesting. I had thought about doing something like that. I had seen something similar done in Linux to find the kernel call table (which isn't an exported symbol). Seems very inelegant though. The fact that windbg and process explorer can see the address at that point implies there must be a nice way to do it.

A loop with system calls to query memory regions, versus bypassing interfaces and directly reading the system loader's internal data structures?  I'd have to say the system calls are cleaner: they use a standard interface, they work regardless of whether the loader is initialized, they do not have to worry about pitfalls involving the loader lock, etc.

Process Explorer is likely getting its information this way as well.  Notice how it shows all mapped files: it does not show only PE images loaded through the system loader.

- Derek

Kris Warkentin

unread,
Sep 26, 2013, 7:14:51 AM9/26/13
to dynamor...@googlegroups.com

That's a very good point. Always better to use documented interfaces when available. No point in being 'sneaky' if I don't have to. I'm thinking VirtualQueryEx is exactly what I'm looking for. Thanks very much.

cheers,

Kris

Kris Warkentin

unread,
Sep 27, 2013, 5:50:26 PM9/27/13
to dynamor...@googlegroups.com
Just wanted to thank you for the tip.

I wrote a loop using NtQueryVirtualMemory() to scan through for SEC_IMAGE sections and was able to find the address with no trouble at all. Didn't need to go near kernel32.dll at all. Much appreciated.

cheers,

Kris
Reply all
Reply to author
Forward
0 new messages