Inject by remote load if there's no IAT on Win8+
Windows 8 and later require the IDT to be within a section when there's no IAT. This prevents relocated imports from working, so we cannot add ourself to the import table. Use `LdrLoadDll` via `CreateRemoteThread` for such a situation.
This commit is contained in:
parent
f4697b59fa
commit
f8509c916c
23
ANSI.c
23
ANSI.c
@ -197,13 +197,14 @@
|
||||
v1.83, 16 February, 2018:
|
||||
create the flush thread on first use.
|
||||
|
||||
v1.84-wip, 17 February, 26 April to 2 May, 2018:
|
||||
v1.84-wip, 17 February, 26 April to 4 May, 2018:
|
||||
close the flush handles on detach;
|
||||
dynamically load WINMM.DLL;
|
||||
use sprintf/_snprintf/_snwprintf instead of wsprintf, avoiding USER32.DLL;
|
||||
replace bsearch (in procrva.c) with specific code;
|
||||
if the primary thread is detached exit the process;
|
||||
get real WriteFile handle before testing for console.
|
||||
get real WriteFile handle before testing for console;
|
||||
use remote load on Win8+ when the process has no IAT.
|
||||
*/
|
||||
|
||||
#include "ansicon.h"
|
||||
@ -2984,7 +2985,7 @@ void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,
|
||||
}
|
||||
else // (type == 48)
|
||||
{
|
||||
InjectDLL64( child_pi );
|
||||
RemoteLoad64( child_pi );
|
||||
}
|
||||
#else
|
||||
#ifdef W32ON64
|
||||
@ -3840,17 +3841,25 @@ void OriginalAttr( PVOID lpReserved )
|
||||
|
||||
// If we were loaded dynamically, remember the current attributes to restore
|
||||
// upon unloading. However, if we're the 64-bit DLL, but the image is 32-
|
||||
// bit, then the dynamic load was due to injecting into AnyCPU.
|
||||
// bit, then the dynamic load was due to injecting into AnyCPU. It may also
|
||||
// be dynamic due to lack of the IAT.
|
||||
if (lpReserved == NULL)
|
||||
{
|
||||
#ifdef _WIN64
|
||||
BOOL dynamic = TRUE;
|
||||
PIMAGE_DOS_HEADER pDosHeader;
|
||||
PIMAGE_NT_HEADERS pNTHeader;
|
||||
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle( NULL );
|
||||
pNTHeader = MakeVA( PIMAGE_NT_HEADERS, pDosHeader->e_lfanew );
|
||||
if (pNTHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
|
||||
#ifdef _WIN64
|
||||
if (pNTHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
|
||||
dynamic = FALSE;
|
||||
else
|
||||
#endif
|
||||
orgattr = ATTR;
|
||||
if (pNTHeader->DATADIRS <= IMAGE_DIRECTORY_ENTRY_IAT &&
|
||||
get_os_version() >= 0x602)
|
||||
dynamic = FALSE;
|
||||
if (dynamic)
|
||||
orgattr = ATTR;
|
||||
GetConsoleMode( hConOut, &orgmode );
|
||||
GetConsoleCursorInfo( hConOut, &orgcci );
|
||||
}
|
||||
|
@ -91,7 +91,7 @@
|
||||
use -pu to unload from the parent.
|
||||
*/
|
||||
|
||||
#define PDATE L"30 April, 2018"
|
||||
#define PDATE L"4 May, 2018"
|
||||
|
||||
#include "ansicon.h"
|
||||
#include "version.h"
|
||||
@ -208,7 +208,7 @@ BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app )
|
||||
else if (type == 32)
|
||||
InjectDLL32( ppi, base );
|
||||
else // (type == 48)
|
||||
InjectDLL64( ppi );
|
||||
RemoteLoad64( ppi );
|
||||
#else
|
||||
wcscpy( DllName + len, L"ANSI32.dll" );
|
||||
set_ansi_dll();
|
||||
|
@ -87,9 +87,10 @@ int ProcessType( LPPROCESS_INFORMATION, PBYTE*, BOOL* );
|
||||
BOOL Wow64Process( HANDLE );
|
||||
|
||||
void InjectDLL( LPPROCESS_INFORMATION, PBYTE );
|
||||
void RemoteLoad32( LPPROCESS_INFORMATION );
|
||||
#ifdef _WIN64
|
||||
void InjectDLL32( LPPROCESS_INFORMATION, PBYTE );
|
||||
void InjectDLL64( LPPROCESS_INFORMATION );
|
||||
void RemoteLoad64( LPPROCESS_INFORMATION );
|
||||
DWORD GetProcRVA( LPCTSTR, LPCSTR, int );
|
||||
#else
|
||||
DWORD GetProcRVA( LPCTSTR, LPCSTR );
|
||||
@ -107,6 +108,7 @@ extern char ansi_dll[MAX_PATH];
|
||||
extern DWORD ansi_len;
|
||||
extern char* ansi_bits;
|
||||
void set_ansi_dll( void );
|
||||
DWORD get_os_version( void );
|
||||
|
||||
extern int log_level;
|
||||
void DEBUGSTR( int level, LPCSTR szFormat, ... );
|
||||
|
110
injdll.c
110
injdll.c
@ -84,6 +84,19 @@ void InjectDLL( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
||||
pNTHeader = (PIMAGE_NT_HEADERS)(pBase + DosHeader.e_lfanew);
|
||||
ReadProcVar( pNTHeader, &NTHeader );
|
||||
|
||||
// Windows 8 and later require the IDT to be part of a section when there's
|
||||
// no IAT. This means we can't move the imports, so remote load instead.
|
||||
if (NTHeader.DATADIRS <= IMAGE_DIRECTORY_ENTRY_IAT &&
|
||||
get_os_version() >= 0x602)
|
||||
{
|
||||
#ifdef _WIN64
|
||||
RemoteLoad64( ppi );
|
||||
#else
|
||||
RemoteLoad32( ppi );
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
import_size = sizeof_imports( ppi, pBase, NTHeader.IMPORTDIR.VirtualAddress );
|
||||
len = 2 * PTRSZ + ansi_len + sizeof(*pImports) + import_size;
|
||||
pImports = HeapAlloc( hHeap, 0, len );
|
||||
@ -173,6 +186,13 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
||||
pNTHeader = (PIMAGE_NT_HEADERS32)(pBase + DosHeader.e_lfanew);
|
||||
ReadProcVar( pNTHeader, &NTHeader );
|
||||
|
||||
if (NTHeader.DATADIRS <= IMAGE_DIRECTORY_ENTRY_IAT &&
|
||||
get_os_version() >= 0x602)
|
||||
{
|
||||
RemoteLoad32( ppi );
|
||||
return;
|
||||
}
|
||||
|
||||
import_size = sizeof_imports( ppi, pBase, NTHeader.IMPORTDIR.VirtualAddress );
|
||||
len = 8 + ansi_len + sizeof(*pImports) + import_size;
|
||||
pImports = HeapAlloc( hHeap, 0, len );
|
||||
@ -232,16 +252,21 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Locate the base address of 64-bit ntdll.dll. This is supposedly really at
|
||||
the same address for every process, but let's find it anyway. A newly-
|
||||
created suspended 64-bit process has two images in memory: the process itself
|
||||
and ntdll.dll - the one that is a DLL must be ntdll.dll. (A 32-bit WOW64
|
||||
process has three images - the process and both 64- & 32-bit ntdll.dll).
|
||||
Locate the base address of ntdll.dll. This is supposedly really at the same
|
||||
address for every process, but let's find it anyway. A newly-created
|
||||
suspended process has two images in memory: the process itself and ntdll.dll.
|
||||
Thus the one that is a DLL must be ntdll.dll. However, a WOW64 process also
|
||||
has the 64-bit version, so test the machine.
|
||||
*/
|
||||
#ifdef _WIN64
|
||||
static PBYTE get_ntdll( LPPROCESS_INFORMATION ppi, WORD machine )
|
||||
#else
|
||||
static PBYTE get_ntdll( LPPROCESS_INFORMATION ppi )
|
||||
#endif
|
||||
{
|
||||
PBYTE ptr;
|
||||
MEMORY_BASIC_INFORMATION minfo;
|
||||
@ -258,7 +283,11 @@ static PBYTE get_ntdll( LPPROCESS_INFORMATION ppi )
|
||||
&& ReadProcVar( (PBYTE)minfo.BaseAddress + dos_header.e_lfanew,
|
||||
&nt_header )
|
||||
&& nt_header.Signature == IMAGE_NT_SIGNATURE
|
||||
&& (nt_header.FileHeader.Characteristics & IMAGE_FILE_DLL))
|
||||
&& (nt_header.FileHeader.Characteristics & IMAGE_FILE_DLL)
|
||||
#ifdef _WIN64
|
||||
&& nt_header.FileHeader.Machine == machine
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return minfo.BaseAddress;
|
||||
}
|
||||
@ -269,7 +298,8 @@ static PBYTE get_ntdll( LPPROCESS_INFORMATION ppi )
|
||||
}
|
||||
|
||||
|
||||
void InjectDLL64( LPPROCESS_INFORMATION ppi )
|
||||
#ifdef _WIN64
|
||||
void RemoteLoad64( LPPROCESS_INFORMATION ppi )
|
||||
{
|
||||
PBYTE ntdll;
|
||||
DWORD rLdrLoadDll;
|
||||
@ -285,7 +315,7 @@ void InjectDLL64( LPPROCESS_INFORMATION ppi )
|
||||
PBYTE* pL;
|
||||
} ip;
|
||||
|
||||
ntdll = get_ntdll( ppi );
|
||||
ntdll = get_ntdll( ppi, IMAGE_FILE_MACHINE_AMD64 );
|
||||
if (ntdll == NULL)
|
||||
return;
|
||||
|
||||
@ -327,3 +357,67 @@ void InjectDLL64( LPPROCESS_INFORMATION ppi )
|
||||
VirtualFreeEx( ppi->hProcess, pMem, 0, MEM_RELEASE );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void RemoteLoad32( LPPROCESS_INFORMATION ppi )
|
||||
{
|
||||
PBYTE ntdll;
|
||||
DWORD rLdrLoadDll;
|
||||
PBYTE pMem;
|
||||
DWORD bMem;
|
||||
DWORD len;
|
||||
HANDLE thread;
|
||||
BYTE code[64];
|
||||
union
|
||||
{
|
||||
PBYTE pB;
|
||||
PUSHORT pS;
|
||||
PDWORD pD;
|
||||
} ip;
|
||||
|
||||
#ifdef _WIN64
|
||||
ntdll = get_ntdll( ppi, IMAGE_FILE_MACHINE_I386 );
|
||||
#else
|
||||
ntdll = get_ntdll( ppi );
|
||||
#endif
|
||||
if (ntdll == NULL)
|
||||
return;
|
||||
|
||||
#ifdef _WIN64
|
||||
rLdrLoadDll = GetProcRVA( L"ntdll.dll", "LdrLoadDll", 32 );
|
||||
#else
|
||||
rLdrLoadDll = GetProcRVA( L"ntdll.dll", "LdrLoadDll" );
|
||||
#endif
|
||||
if (rLdrLoadDll == 0)
|
||||
return;
|
||||
|
||||
pMem = VirtualAllocEx( ppi->hProcess, NULL, 4096, MEM_COMMIT,
|
||||
PAGE_EXECUTE_READ );
|
||||
if (pMem == NULL)
|
||||
{
|
||||
DEBUGSTR(1, " Failed to allocate virtual memory (%u)", GetLastError());
|
||||
return;
|
||||
}
|
||||
bMem = PtrToUint( pMem );
|
||||
|
||||
len = (DWORD)TSIZE(wcslen( DllName ) + 1);
|
||||
ip.pB = code;
|
||||
|
||||
*ip.pS++ = 0x5451; // push ecx esp
|
||||
*ip.pB++ = 0x68; // push
|
||||
*ip.pD++ = bMem + 20; // L"path\to\ANSI32.dll"
|
||||
*ip.pD++ = 0x006A006A; // push 0 0
|
||||
*ip.pB++ = 0xe8; // call LdrLoadDll
|
||||
*ip.pD++ = PtrToUint( ntdll ) + rLdrLoadDll - (bMem + 16);
|
||||
*ip.pD++ = 0xc359; // pop ecx / ret and padding
|
||||
*ip.pS++ = (USHORT)(len - TSIZE(1)); // UNICODE_STRING.Length
|
||||
*ip.pS++ = (USHORT)len; // UNICODE_STRING.MaximumLength
|
||||
*ip.pD++ = bMem + 28; // UNICODE_STRING.Buffer
|
||||
WriteProcMem( pMem, code, ip.pB - code );
|
||||
WriteProcMem( pMem + (ip.pB - code), DllName, len );
|
||||
thread = CreateRemoteThread( ppi->hProcess, NULL, 4096,
|
||||
(LPTHREAD_START_ROUTINE)pMem, NULL, 0, NULL );
|
||||
WaitForSingleObject( thread, INFINITE );
|
||||
CloseHandle( thread );
|
||||
VirtualFreeEx( ppi->hProcess, pMem, 0, MEM_RELEASE );
|
||||
}
|
||||
|
@ -70,9 +70,9 @@ LIBS = advapi32.lib $(LIBS64)
|
||||
# Identify ansicon.exe using "ANSI" as a version number.
|
||||
LINK = /link /version:20033.18771
|
||||
|
||||
X86OBJS = x86\injdll.obj x86\proctype.obj x86\util.obj
|
||||
X64OBJS = x64\injdll.obj x64\proctype.obj x64\util.obj x64\procrva.obj
|
||||
X6432OBJS = x86\injdll.obj x64\proctype32.obj x86\util.obj
|
||||
X86OBJS = x86\injdll.obj x86\procrva.obj x86\proctype.obj x86\util.obj
|
||||
X64OBJS = x64\injdll.obj x64\procrva.obj x64\proctype.obj x64\util.obj
|
||||
X6432OBJS = x86\injdll.obj x86\procrva.obj x64\proctype32.obj x86\util.obj
|
||||
|
||||
!IF !DEFINED(V)
|
||||
V = 0
|
||||
@ -99,7 +99,7 @@ ansicon64: x64 x64\ansicon.exe x64\ANSI64.dll
|
||||
x86:
|
||||
mkdir x86
|
||||
|
||||
x86\ansicon.exe: x86\ansicon.obj $(X86OBJS) x86\procrva.obj x86\ansicon.res
|
||||
x86\ansicon.exe: x86\ansicon.obj $(X86OBJS) x86\ansicon.res
|
||||
$(LDmsg)$(CC) /nologo $(SHARE) /Fe$@ $** $(LIBS) $(LINK) /filealign:512
|
||||
!IF "$(_NMAKE_VER)" == "9.00.30729.01"
|
||||
$(MTmsg)$(MT) /nologo -manifest $@.manifest -outputresource:$@;1
|
||||
|
@ -339,10 +339,10 @@ Version History
|
||||
|
||||
Legend: + added, - bug-fixed, * changed.
|
||||
|
||||
1.84-wip - 3 May, 2018:
|
||||
1.84-wip - 4 May, 2018:
|
||||
- close the flush handles on detach;
|
||||
- use remote load on Win8+ if the process has no IAT;
|
||||
- WriteFile wasn't properly testing if its handle was for a console;
|
||||
- use remote load on Win8+ if the process has no IAT;
|
||||
* remove dependency on USER32, dynamically load WINMM;
|
||||
* exit process if the primary thread is detached (for processes on Win10
|
||||
that return, rather than call ExitProcess).
|
||||
@ -621,4 +621,4 @@ Distribution
|
||||
|
||||
|
||||
========================
|
||||
Jason Hood, 3 May, 2018.
|
||||
Jason Hood, 4 May, 2018.
|
||||
|
14
util.c
14
util.c
@ -74,6 +74,20 @@ void set_ansi_dll( void )
|
||||
}
|
||||
|
||||
|
||||
// GetVersion and GetVersionEx use Win32VersionValue from the header, which
|
||||
// could be anything. Retrieve the OS version from NTDLL's header.
|
||||
DWORD get_os_version( void )
|
||||
{
|
||||
PIMAGE_DOS_HEADER pDosHeader;
|
||||
PIMAGE_NT_HEADERS pNTHeader;
|
||||
|
||||
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle( L"ntdll.dll" );
|
||||
pNTHeader = MakeVA( PIMAGE_NT_HEADERS, pDosHeader->e_lfanew );
|
||||
return pNTHeader->OptionalHeader.MajorOperatingSystemVersion << 8 |
|
||||
pNTHeader->OptionalHeader.MinorOperatingSystemVersion;
|
||||
}
|
||||
|
||||
|
||||
static LPSTR buf;
|
||||
static DWORD buf_len;
|
||||
static BOOL quote, alt;
|
||||
|
Loading…
x
Reference in New Issue
Block a user