Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows 7 x64 - InjMethodThunk method failing in ntdll!RtlEqualUnicodeString due to AV #10

Open
tantoinet opened this issue Jun 14, 2019 · 3 comments

Comments

@tantoinet
Copy link

tantoinet commented Jun 14, 2019

Hello,

The InjMethodThunk method is failing on Win7 x64 (both updated 6.1.7601.24387 ntdll.dll and non updated 6.1.7601.17514) when loading a wow64 process. All native x64 processes are loaded and injected fine.
This leads to an access violation error.

Some debug output:
The original shellcode looks broken for me. I've updated it with the following one (but still failing):
0x83, 0xec, 0x0c, // sub esp,0xc
0x0f, 0xb7, 0x44, 0x24, 0x18, // movzx eax,[esp + 0x18]
0x66, 0x89, 0x04, 0x24, // mov [esp],ax
0x66, 0x89, 0x44, 0x24, 0x02, // mov [esp + 0x2],ax
0x8b, 0x44, 0x24, 0x14, // mov eax,[esp + 0x14]
0x89, 0x44, 0x24, 0x04, // mov [esp + 0x4],eax
0x8d, 0x44, 0x24, 0x08, // lea eax,[esp + 0x8]
0x50, // push eax
0x8d, 0x44, 0x24, 0x04, // lea eax,[esp + 0x04]
0x50, // push eax
0x6a, 0x00, // push 0x0
0x6a, 0x00, // push 0x0
0xff, 0x54, 0x24, 0x20, // call [esp + 0x20]
0x83, 0xc4, 0x0c, // add esp,0xc
0xc2, 0x0c, 0x00, // ret 0xc

0:000> g
ModLoad: 0000000077a10000 0000000077b2f000 WOW64_IMAGE_SECTION
ModLoad: 0000000076190000 00000000762a0000 WOW64_IMAGE_SECTION
ModLoad: 0000000077a10000 0000000077b2f000 NOT_AN_IMAGE
ModLoad: 0000000077910000 0000000077a0a000 NOT_AN_IMAGE
(b6c.eb4): WOW64 breakpoint - code 4000001f (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
00010000 cc int 3
0:000:x86> u
00010000 cc int 3
00010001 83ec0c sub esp,0Ch
00010004 0fb7442418 movzx eax,word ptr [esp+18h]
00010009 66890424 mov word ptr [esp],ax
0001000d 6689442402 mov word ptr [esp+2],ax
00010012 8b442414 mov eax,dword ptr [esp+14h]
00010016 89442404 mov dword ptr [esp+4],eax
0001001a 8d442408 lea eax,[esp+8]
0:000:x86> dd esp L8
0018fd08 77d0007d 77d2eaea 00010032 00000062
0018fd18 00010003 00000000 00000000 00000000
0:000:x86> ln poi(esp)
(77d00058) ntdll32!KiUserApcDispatcher+0x25 | (77d000a0) ntdll32!KiUserCallbackExceptionHandler
0:000:x86> du poi(esp+8)
00010032 "C:\Users\tant\Desktop\bin\x64\De"
00010072 "bug\injdllx86.dll"

Before calling LdrLoadDll, the stack seems having the correct arguments:
00010028 ff542420 call dword ptr [esp+20h] ss:002b:0018fd0c={ntdll32!LdrLoadDll (77d2eaea)}
0:000:x86> dd esp LC
0018fcec 00000000 00000000 0018fcfc 0018fd04
0018fcfc 00620062 00010032 00000000 77d0007d
0018fd0c 77d2eaea 00010032 00000062 00010003

Where:
PVOID BaseAddress == 0x0018fd04;
DllName.Length = (USHORT)SystemArgument2 = 0x0062;
DllName.MaximumLength = (USHORT)SystemArgument2 = 0x0062;
DllName.Buffer = (PWSTR) SystemArgument1 = 0x0018fcfc;

Then an access violation occurs in RtlEqualUnicodeString
0:000:x86> g
(b6c.eb4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
ntdll32!RtlEqualUnicodeString+0x10:
77d1e8cb 0fb732 movzx esi,word ptr [edx] ds:002b:00000024=????

With the following call stack:
0:000:x86> kp
ChildEBP RetAddr
0018fa14 77d2bc57 ntdll32!RtlEqualUnicodeString+0x10
0018fa34 77d2e737 ntdll32!LdrpFindLoadedDllByName+0x9d
0018fb1c 77d2e946 ntdll32!LdrpFindOrMapDll+0x1e5
0018fca8 77d6d3df ntdll32!LdrpLoadDll+0x2d6
0018fce4 0001002c ntdll32!LdrLoadDll+0xc7
WARNING: Frame IP not in any known module. Following frames may be wrong.
00000000 00000000 0x1002c

It seems that RtlEqualUnicodeString is getting invalid arguments:
0:000:x86> dd ebp L8
0018fa14 0018fa34 77d2bc57 0018fb70 00000024
0018fa24 00000001 00000000 00000002 00000000
0:000:x86> dd poi(ebp+8) L2
0018fb70 00620062 00010032 <== this is our DllName struct
0:000:x86> dd poi(ebp+c) L2
00000024 ???????? ???????? <== this is a broken UNICODE_STRING, coming from somewhere.

@tantoinet tantoinet changed the title Windows 7 x64 - Thunk based injection method failing Jun 14, 2019
@tantoinet
Copy link
Author

Inside ntdll!LdrpFindLoadedDllByName function we have:
ntdll32!LdrpFindLoadedDllByName+0x7d:
77a9bc2d 395d0c cmp dword ptr [ebp+0Ch],ebx
77a9bc30 0f84f8f4ffff je ntdll32!LdrpFindLoadedDllByName+0x45 (77a9b12e)
77a9bc36 8b350c02b677 mov esi,dword ptr [ntdll32!PebLdr+0xc (77b6020c)]
77a9bc3c bf0c02b677 mov edi,offset ntdll32!PebLdr+0xc (77b6020c)
77a9bc41 3bf7 cmp esi,edi
77a9bc43 0f84e5f4ffff je ntdll32!LdrpFindLoadedDllByName+0x45 (77a9b12e)
77a9bc49 6a01 push 1
77a9bc4b 8d4624 lea eax,[esi+24h]
77a9bc4e 50 push eax
77a9bc4f ff750c push dword ptr [ebp+0Ch]
77a9bc52 e8642cffff call ntdll32!RtlEqualUnicodeString (77a8e8bb)
77a9bc57 84c0 test al,al

Where it's reading the ntdll32!PebLdr+0xc which is InLoadOrderModuleList. However, it's value is null.
This is initialized in ntdll32!LdrpInitializeProcess, however, this function is never called when the actually required dlls are loaded:

  • ntdll.dll
  • ntdll32.dll
  • wow64.dll
  • wow64win.dll
  • wow64cpu.dll

To fix this, we need to add another dependency on kernel32.dll, which is the following dll to be loaded.
Once done, we have the following call stack before our Thunk/shellcode gets called:
0:000:x86> kp
ChildEBP RetAddr
0018fcb0 77aa9f11 ntdll32!LdrpInitializeProcess
0018fd00 77a99789 ntdll32!_LdrpInitialize+0x78
0018fd10 00000000 ntdll32!LdrInitializeThunk+0x10

This does the job and fixes the issue :)
Btw, I've tested again with the original shellcode and it's working. I will spend more time understanding it.

@wbenny
Copy link
Owner

wbenny commented Jun 14, 2019

Hi!

To fix this, we need to add another dependency on kernel32.dll, which is the following dll to be loaded.
Once done, we have the following call stack before our Thunk/shellcode gets called

...this is true and the case is handled here:
https://github.com/wbenny/injdrv/blob/master/src/injlib/injlib.c#L1424

I'm quite confused now... so is injdrv working "as it is" for you or not? :)

@tantoinet
Copy link
Author

tantoinet commented Jun 14, 2019

No, i think that the dependency you mentionned isn't bulletproof.
On my Win7 box, I'm having apisetschema.dll being loaded before kernel32.dll which doesn't meet that condition, hence trigger the injection too early.

I've solved this by using:

typedef enum _INJ_SYSTEM_DLL
{
  INJ_NOTHING_LOADED            = 0x0000,
  INJ_SYSARM32_NTDLL_LOADED     = 0x0001,
  INJ_SYCHPE32_NTDLL_LOADED     = 0x0002,
  INJ_SYSWOW64_NTDLL_LOADED     = 0x0004,
  INJ_SYSTEM32_NTDLL_LOADED     = 0x0008,
  INJ_SYSTEM32_WOW64_LOADED     = 0x0010,
  INJ_SYSTEM32_WOW64WIN_LOADED  = 0x0020,
  INJ_SYSTEM32_WOW64CPU_LOADED  = 0x0040,
  INJ_SYSTEM32_WOWARMHW_LOADED  = 0x0080,
  INJ_SYSTEM32_XTAJIT_LOADED    = 0x0100,
  INJ_SYSTEM32_KERNEL32_LOADED  = 0x0200,
} INJ_SYSTEM_DLL;

and

INJ_SYSTEM_DLL_DESCRIPTOR InjpSystemDlls[] = {
  { RTL_CONSTANT_STRING(L"\\SysArm32\\ntdll.dll"),    INJ_SYSARM32_NTDLL_LOADED    },
  { RTL_CONSTANT_STRING(L"\\SyChpe32\\ntdll.dll"),    INJ_SYCHPE32_NTDLL_LOADED    },
  { RTL_CONSTANT_STRING(L"\\SysWow64\\ntdll.dll"),    INJ_SYSWOW64_NTDLL_LOADED    },
  { RTL_CONSTANT_STRING(L"\\System32\\ntdll.dll"),    INJ_SYSTEM32_NTDLL_LOADED    },
  { RTL_CONSTANT_STRING(L"\\System32\\wow64.dll"),    INJ_SYSTEM32_WOW64_LOADED    },
  { RTL_CONSTANT_STRING(L"\\System32\\wow64win.dll"), INJ_SYSTEM32_WOW64WIN_LOADED },
  { RTL_CONSTANT_STRING(L"\\System32\\wow64cpu.dll"), INJ_SYSTEM32_WOW64CPU_LOADED },
  { RTL_CONSTANT_STRING(L"\\System32\\wowarmhw.dll"), INJ_SYSTEM32_WOWARMHW_LOADED },
  { RTL_CONSTANT_STRING(L"\\System32\\xtajit.dll"),   INJ_SYSTEM32_XTAJIT_LOADED   },
  { RTL_CONSTANT_STRING(L"\\System32\\kernel32.dll"), INJ_SYSTEM32_KERNEL32_LOADED },
};

and

#   if defined (_M_AMD64)

    RequiredDlls |= INJ_SYSTEM32_WOW64CPU_LOADED;
    RequiredDlls |= INJ_SYSTEM32_KERNEL32_LOADED;
    RequiredDlls |= INJ_SYSWOW64_NTDLL_LOADED;

#   elif defined (_M_ARM64)

Which is much better :)
Btw, you may probably want to get rid of the condition you mentionned.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
2 participants