Go back to using ANSI-LLW.exe.

This commit is contained in:
Jason Hood 2013-02-14 18:12:13 +10:00
parent a52a46c9c1
commit c5cb4788c2
8 changed files with 98 additions and 114 deletions

23
ANSI-LLW.asm Normal file
View File

@ -0,0 +1,23 @@
; ANSI-LLW.asm - Output the 32-bit address of LoadLibraryW.
;
; Jason Hood, 1 February, 2013.
;
; A FASM (flatassembler.net) version of the C code, which virus scanners didn't
; like for some reason.
format PE Console 4.0
include 'win32a.inc'
mov eax, [LoadLibraryW]
ret
data import
library kernel32,'KERNEL32.DLL'
import kernel32,\
LoadLibraryW,'LoadLibraryW'
end data

22
ANSI-LLW.c Normal file
View File

@ -0,0 +1,22 @@
/*
ANSI-LLW.c - Output the 32-bit address of LoadLibraryW.
Jason Hood, 13 November, 2010 (LLA version 5 September, 2010).
I don't know of a method to retrieve the 32-bit address of a function in
64-bit code, so this is a simple workaround.
18 December, 2010: Initially I used GetProcAddress, but then I thought that
was silly, why don't I just return LoadLibraryW directly? That worked fine
for TDM64 and VC, but MinGW32 would return the address of the jump to the
function, not the function itself. Not so silly after all.
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
int main( void )
{
return (DWORD)GetProcAddress( GetModuleHandle( "kernel32.dll" ),
"LoadLibraryW" );
}

3
ANSI.c
View File

@ -95,6 +95,9 @@
v1.60, 22 to 24 November, 2012: v1.60, 22 to 24 November, 2012:
alternative method to obtain LLW for 64->32 injection; alternative method to obtain LLW for 64->32 injection;
support for VC6 (remove section pragma, rename isdigit to is_digit). support for VC6 (remove section pragma, rename isdigit to is_digit).
v1.61, 14 February, 2013:
go back to using ANSI-LLW.exe for 64->32 injection.
*/ */
#include "ansicon.h" #include "ansicon.h"

View File

@ -71,7 +71,7 @@
write the date if appending to the log. write the date if appending to the log.
*/ */
#define PDATE L"24 November, 2012" #define PDATE L"14 February, 2013"
#include "ansicon.h" #include "ansicon.h"
#include "version.h" #include "version.h"

View File

@ -32,96 +32,9 @@ TWow64SetThreadContext Wow64SetThreadContext;
#define GetThreadContext Wow64GetThreadContext #define GetThreadContext Wow64GetThreadContext
#define SetThreadContext Wow64SetThreadContext #define SetThreadContext Wow64SetThreadContext
#define MakeVA( cast, offset ) (cast)((DWORD_PTR)base + (DWORD)(offset)) extern
extern DWORD LLW32;
LPVOID base;
int export_cmp( const void* a, const void* b )
{
return strcmp( (LPCSTR)a, MakeVA( LPCSTR, *(const PDWORD)b ) );
}
/*
Get the address of the 32-bit LoadLibraryW function from 64-bit code. This
was originally done via executing a helper program (ANSI-LLW.exe), but for
some reason, virus scanners really didn't like it (even when I rewrote it in
assembly so it was 1024 bytes and literally two instructions, virustotal
still had three scanners complaining). Now I do it the "hard" way - load the
32-bit kernel32.dll directly and search the exports. Even worse, it seems
Wow64 loads kernel32.dll at a different base address each boot (at least, I
hope it only changes each boot). Fortunately, loading the DLL as an image in
64-bit code seems to use the 32-bit address.
*/
BOOL get_LLW32( void )
{
HMODULE kernel32;
TCHAR buf[MAX_PATH];
UINT len;
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS32 pNTHeader;
PIMAGE_EXPORT_DIRECTORY pExportDir;
PDWORD fun_table, name_table;
PWORD ord_table;
PDWORD pLLW;
len = GetSystemWow64Directory( buf, MAX_PATH );
wcscpy( buf + len, L"\\kernel32.dll" );
// MinGW-w64 has a typo, calling it LINRARY.
kernel32 = LoadLibraryEx( buf, NULL, 0x20/*LOAD_LIBRARY_AS_IMAGE_RESOURCE*/ );
if (kernel32 == NULL)
{
DEBUGSTR( 1, L"Unable to load 32-bit kernel32.dll!" );
return FALSE;
}
// The handle uses low bits as flags, so strip 'em off.
base = (LPVOID)((DWORD_PTR)kernel32 & 0xFFFF0000);
// Tests to make sure we're looking at a module image (the 'MZ' header)
pDosHeader = (PIMAGE_DOS_HEADER)base;
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
DEBUGSTR( 1, L"Image has no DOS header!" );
return FALSE;
}
// The MZ header has a pointer to the PE header
pNTHeader = MakeVA( PIMAGE_NT_HEADERS32, pDosHeader->e_lfanew );
// One more test to make sure we're looking at a "PE" image
if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
{
DEBUGSTR( 1, L"Image has no NT header!" );
return FALSE;
}
// We now have a valid pointer to the module's PE header.
// Get a pointer to its exports section.
pExportDir = MakeVA( PIMAGE_EXPORT_DIRECTORY,
pNTHeader->OptionalHeader.
DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].
VirtualAddress );
fun_table = MakeVA( PDWORD, pExportDir->AddressOfFunctions );
name_table = MakeVA( PDWORD, pExportDir->AddressOfNames );
ord_table = MakeVA( PWORD, pExportDir->AddressOfNameOrdinals );
pLLW = bsearch( "LoadLibraryW", name_table, pExportDir->NumberOfNames,
sizeof(DWORD), export_cmp );
if (pLLW == NULL)
{
DEBUGSTR( 1, L"Could not find LoadLibraryW!" );
return FALSE;
}
LLW32 = MakeVA( DWORD, fun_table[ord_table[pLLW - name_table]] );
FreeLibrary( kernel32 );
return TRUE;
}
#else
DWORD LLW32;
#endif #endif
DWORD LLW32;
void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll ) void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
@ -138,6 +51,22 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
PDWORD pL; PDWORD pL;
} ip; } ip;
#ifdef IMPORT_WOW64
if (Wow64GetThreadContext == 0)
{
#define GETPROC( proc ) proc = (T##proc)GetProcAddress( hKernel, #proc )
HMODULE hKernel = GetModuleHandle( L"kernel32.dll" );
GETPROC( Wow64GetThreadContext );
GETPROC( Wow64SetThreadContext );
// Assume if one is defined, so is the other.
if (Wow64GetThreadContext == 0)
{
DEBUGSTR( 1, L"Failed to get pointer to Wow64GetThreadContext." );
return;
}
}
#endif
len = TSIZE(lstrlen( dll ) + 1); len = TSIZE(lstrlen( dll ) + 1);
if (len > TSIZE(MAX_PATH)) if (len > TSIZE(MAX_PATH))
return; return;
@ -145,28 +74,29 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
if (LLW32 == 0) if (LLW32 == 0)
{ {
#ifdef _WIN64 #ifdef _WIN64
if (!get_LLW32()) STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
// ...ANSI32.dll\0
CopyMemory( code, dll, len - TSIZE(7) );
// ...ANSI-LLW.exe\0
CopyMemory( code + len - TSIZE(7), L"-LLW.exe", TSIZE(9) );
if (!CreateProcess( (LPCTSTR)code, NULL, NULL, NULL, FALSE, 0, NULL, NULL,
&si, &pi ))
{
DEBUGSTR( 1, L"Failed to execute \"%s\".", (LPCTSTR)code );
return; return;
}
WaitForSingleObject( pi.hProcess, INFINITE );
GetExitCodeProcess( pi.hProcess, &LLW32 );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
#else #else
LLW32 = (DWORD)GetProcAddress( GetModuleHandleA( "kernel32.dll" ), LLW32 = (DWORD)GetProcAddress( GetModuleHandle( L"kernel32.dll" ),
"LoadLibraryW" ); "LoadLibraryW" );
#endif #endif
} }
#ifdef IMPORT_WOW64
if (Wow64GetThreadContext == 0)
{
#define GETPROC( proc ) proc = (T##proc)GetProcAddress( hKernel, #proc )
HMODULE hKernel = GetModuleHandleA( "kernel32.dll" );
GETPROC( Wow64GetThreadContext );
GETPROC( Wow64SetThreadContext );
// Assume if one is defined, so is the other.
if (Wow64GetThreadContext == 0)
{
DEBUGSTR( 1, L"Failed to get pointer to Wow64GetThreadContext.\n" );
return;
}
}
#endif
CopyMemory( code + CODESIZE, dll, len ); CopyMemory( code + CODESIZE, dll, len );
len += CODESIZE; len += CODESIZE;

View File

@ -36,7 +36,7 @@ all: ansicon32 ansicon64
ansicon32: x86 x86/ansicon.exe x86/ANSI32.dll ansicon32: x86 x86/ansicon.exe x86/ANSI32.dll
ansicon64: x64 x64/ansicon.exe x64/ANSI64.dll x64/ANSI32.dll ansicon64: x64 x64/ansicon.exe x64/ANSI64.dll x64/ANSI32.dll x64/ANSI-LLW.exe
x86: x86:
cmd /c "mkdir x86" cmd /c "mkdir x86"
@ -59,6 +59,9 @@ x64/ANSI64.dll: x64/ANSI.o $(X64OBJS) x64/ansiv.o
x64/ANSI32.dll: x64/ANSI32.o x64/proctype32.o x86/injdll32.o x86/util.o x86/ansiv.o x64/ANSI32.dll: x64/ANSI32.o x64/proctype32.o x86/injdll32.o x86/util.o x86/ansiv.o
$(CC) -m32 $+ -s -o $@ -mdll -Wl,-shared,--image-base,0xAC0000 $(CC) -m32 $+ -s -o $@ -mdll -Wl,-shared,--image-base,0xAC0000
x64/ANSI-LLW.exe: ANSI-LLW.c
$(CC) -m32 $(CFLAGS) $< -s -o $@
x86/ansicon.o: version.h x86/ansicon.o: version.h
x86/ANSI.o: version.h x86/ANSI.o: version.h
x64/ansicon.o: version.h x64/ansicon.o: version.h

View File

@ -63,7 +63,7 @@ X64OBJS = x64\proctype.obj x64\injdll64.obj x64\injdll32.obj x64\util.obj
all: ansicon$(BITS) all: ansicon$(BITS)
ansicon32: x86 x86\ansicon.exe x86\ANSI32.dll x64\ANSI32.dll ansicon32: x86 x86\ansicon.exe x86\ANSI32.dll x64 x64\ANSI32.dll x64\ANSI-LLW.exe
ansicon64: x64 x64\ansicon.exe x64\ANSI64.dll ansicon64: x64 x64\ansicon.exe x64\ANSI64.dll
@ -88,6 +88,9 @@ x64\ANSI64.dll: x64\ANSI.obj $(X64OBJS) x64\ansi.res
x64\ANSI32.dll: x64\ANSI32.obj x64\proctype32.obj x86\injdll32.obj x86\util.obj x86\ansi.res x64\ANSI32.dll: x64\ANSI32.obj x64\proctype32.obj x86\injdll32.obj x86\util.obj x86\ansi.res
$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link /base:0xAC0000 /section:.shared,s /filealign:512 $(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link /base:0xAC0000 /section:.shared,s /filealign:512
x64\ANSI-LLW.exe: ANSI-LLW.c
$(CC) $(CFLAGS) /Fe$@ /Fo$*.obj $? $(LIBS64)
ansicon.c: ansicon.h version.h ansicon.c: ansicon.h version.h
ansicon.rc: version.h ansicon.rc: version.h
ANSI.c: ansicon.h version.h ANSI.c: ansicon.h version.h

View File

@ -2,8 +2,8 @@
version.h - Version defines. version.h - Version defines.
*/ */
#define PVERS L"1.60" // wide string #define PVERS L"1.61" // wide string
#define PVERSA "1.60" // ANSI string (windres 2.16.91 didn't like L) #define PVERSA "1.61" // ANSI string (windres 2.16.91 didn't like L)
#define PVERE L"160" // wide environment string #define PVERE L"161" // wide environment string
#define PVEREA "160" // ANSI environment string #define PVEREA "161" // ANSI environment string
#define PVERB 1,6,0,0 // binary (resource) #define PVERB 1,6,1,0 // binary (resource)