untested but same idea ( no fix-ups needed in the injected code )
15011370 6A 01 PUSH 1
15011372 FF15 68014900 CALL DWORD PTR DS:[490168] // Sleep in exe IAT
15011378 EB E3 JMP SHORT 1501135D
1501137A 90 NOP
1501137B 90 NOP
data[] = { 0x6A, 0x01, 0xFF, 0x15, 0x68, 0x01, 0x49, 0x00, 0xEB, 0xE3, 0x90, 0x90 };
Oh cool.
Somehow missed this thread last year. Must have been busy having a mental breakdown at the time...
Anyway, this is totally the way to go. You can never reliably hard code procedure entry points in external modules. They can be re-mapped by the OS, but in fact almost never are. The other problem is different versions of the same module will shift the entry points for the individual procedures even if the module is mapped at the same base address.
In theory modules can be re-mapped by the OS and they will be in the case where multiple 3rd party modules attempt to use the same address space, but AFAIK for core API modules the only time M$ seriously tried to impliment this was for Vista. It was supposed to be a security feature but ended up being a Pandora's Box of cascading bugs that eventually imploded the whole OS.
But as aqrit points out, the only way to go when linking procedure calls is to use the correct import/export structures. You can always get these from the IMAGE_EXPORT_DIRECTORY but if the proc you want is already imported by the target application, then its much easier to just us the Import Address Table, as the system loader will have already done the work for you.
In the case of WC2 it already imports a fairly decent list of handy API functions, but most notably it imports both LoadLibrary and GetProcAddress. Obviously when you have access to there 2 functions you can always import anything you want to.
the "call DWORD ptr[IAT offset]" method is ideal for injected code. When doing this type of thing I find it handy to to just define the proc names as equates then you only need to add the square brackets to call instructions. i.e.
Sleep equ 490168h
.code
push 50
call [Sleep]
If you keep your equates in a seperate include, you can swap them in/out in exchange for standard API includes which helps when testing/compiling for injection.
So how did this end up going? I tested it on my system and it seemed to work well in-game, but not in the chat channel. Did this ever end up being fixed?
Here's an ASM include for the Kernel32 procs imported by WC2:; CloseHandle(HANDLE hObject)
CloseHandle equ 490160h
; CompareStringA(LCID Locale,DWORD dwCmpFlags,LPCSTR lpString1,int cchCount1,LPCSTR lpString2,int cchCount2)
CompareStringA equ 490088h
; CompareStringW(LCID Locale,DWORD dwCmpFlags,LPCWSTR lpString1,int cchCount1,LPCWSTR lpString2,int cchCount2)
CompareStringW equ 490084h
; CreateDirectoryA(LPCSTR lpPathName,LPSECURITY_ATTRIBUTES lpSecurityAttributes)
CreateDirectoryA equ 490078h
; CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes,BOOL bManualReset,BOOL bInitialState,LPCSTR lpName)
CreateEventA equ 490190h
; CreateFileA(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile)
CreateFileA equ 490164h
; CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId)
CreateThread equ 49012Ch
; DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
DeleteCriticalSection equ 490170h
; DeleteFileA(LPCSTR lpFileName)
DeleteFileA equ 490140h
; EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
EnterCriticalSection equ 490184h
; ExitProcess(UINT uExitCode)
ExitProcess equ 490114h
; ExitThread(DWORD dwExitCode)
ExitThread equ 490120h
; FileTimeToLocalFileTime(const FILETIME *lpFileTime,LPFILETIME lpLocalFileTime)
FileTimeToLocalFileTime equ 4901F8h
; FileTimeToSystemTime(const FILETIME *lpFileTime,LPSYSTEMTIME lpSystemTime)
FileTimeToSystemTime equ 4901F4h
; FindClose(HANDLE hFindFile)
FindClose equ 490144h
; FindFirstFileA(LPCSTR lpFileName,LPWIN32_FIND_DATAA lpFindFileData)
FindFirstFileA equ 49014Ch
; FindNextFileA(HANDLE hFindFile,LPWIN32_FIND_DATAA lpFindFileData)
FindNextFileA equ 490148h
; FlushFileBuffers(HANDLE hFile)
FlushFileBuffers equ 490090h
; FormatMessageA(DWORD dwFlags,LPCVOID lpSource,DWORD dwMessageId,DWORD dwLanguageId,LPSTR lpBuffer,DWORD nSize,va_list *Arguments)
FormatMessageA equ 4901D0h
; FreeEnvironmentStringsA(LPSTR)
FreeEnvironmentStringsA equ 4900CCh
; FreeEnvironmentStringsW(LPWSTR)
FreeEnvironmentStringsW equ 4900C8h
; FreeLibrary(HMODULE hLibModule)
FreeLibrary equ 4901B0h
; GetACP(void)
GetACP equ 4900E0h
; GetCPInfo(UINT CodePage,LPCPINFO lpCPInfo)
GetCPInfo equ 4900E4h
; GetCommState(HANDLE hFile,LPDCB lpDCB)
GetCommState equ 4901A0h
; GetCommandLineA(void)
GetCommandLineA equ 490154h
; GetComputerNameA(LPSTR lpBuffer,LPDWORD nSize)
GetComputerNameA equ 490074h
; GetCurrentProcess(void)
GetCurrentProcess equ 490058h
; GetCurrentThreadId(void)
GetCurrentThreadId equ 490128h
; GetDateFormatA(LCID Locale,DWORD dwFlags,const SYSTEMTIME *lpDate,LPCSTR lpFormat,LPSTR lpDateStr,int cchDate)
GetDateFormatA equ 4901F0h
; GetDiskFreeSpaceA(LPCSTR lpRootPathName,LPDWORD lpSectorsPerCluster,LPDWORD lpBytesPerSector,LPDWORD lpNumberOfFreeClusters,LPDWORD lpTotalNumberOfClusters)
GetDiskFreeSpaceA equ 4901DCh
; GetDriveTypeA(LPCSTR lpRootPathName)
GetDriveTypeA equ 490158h
; GetEnvironmentStrings(void)
GetEnvironmentStrings equ 4900C4h
; GetEnvironmentStringsW(void)
GetEnvironmentStringsW equ 4900C0h
; GetEnvironmentVariableA(LPCSTR lpName,LPSTR lpBuffer,DWORD nSize)
GetEnvironmentVariableA equ 4900B8h
; GetFileAttributesA(LPCSTR lpFileName)
GetFileAttributesA equ 4901FCh
; GetFileSize(HANDLE hFile,LPDWORD lpFileSizeHigh)
GetFileSize equ 490070h
; GetFileType(HANDLE hFile)
GetFileType equ 4900BCh
; GetLastError(void)
GetLastError equ 490150h
; GetLocalTime(LPSYSTEMTIME lpSystemTime)
GetLocalTime equ 490134h
; GetLogicalDriveStringsA(DWORD nBufferLength,LPSTR lpBuffer)
GetLogicalDriveStringsA equ 49015Ch
; GetModuleFileNameA(HMODULE hModule,LPSTR lpFilename,DWORD nSize)
GetModuleFileNameA equ 49013Ch
; GetModuleHandleA(LPCSTR lpModuleName)
GetModuleHandleA equ 4901C0h
; GetOEMCP(void)
GetOEMCP equ 4900DCh
; GetOverlappedResult(HANDLE hFile,LPOVERLAPPED lpOverlapped,LPDWORD lpNumberOfBytesTransferred,BOOL bWait)
GetOverlappedResult equ 4901B4h
; GetProcAddress(HMODULE hModule,LPCSTR lpProcName)
GetProcAddress equ 490174h
; GetStartupInfoA(LPSTARTUPINFOA lpStartupInfo)
GetStartupInfoA equ 49011Ch
; GetStdHandle(DWORD nStdHandle)
GetStdHandle equ 490060h
; GetStringTypeA(LCID Locale,DWORD dwInfoType,LPCSTR lpSrcStr,int cchSrc,LPWORD lpCharType)
GetStringTypeA equ 4900A4h
; GetStringTypeW(DWORD dwInfoType,LPCWSTR lpSrcStr,int cchSrc,LPWORD lpCharType)
GetStringTypeW equ 4900A0h
; GetSystemInfo(LPSYSTEM_INFO lpSystemInfo)
GetSystemInfo equ 4901E0h
; GetSystemTime(LPSYSTEMTIME lpSystemTime)
GetSystemTime equ 4901ACh
; GetTickCount(void)
GetTickCount equ 490138h
; GetTimeFormatA(LCID Locale,DWORD dwFlags,const SYSTEMTIME *lpTime,LPCSTR lpFormat,LPSTR lpTimeStr,int cchTime)
GetTimeFormatA equ 4901ECh
; GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation)
GetTimeZoneInformation equ 4901E4h
; GetVersion(void)
GetVersion equ 490068h
; GetVersionExA(LPOSVERSIONINFOA lpVersionInformation)
GetVersionExA equ 4900B4h
; GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer)
GlobalMemoryStatus equ 4901D8h
; HeapAlloc(HANDLE hHeap,DWORD dwFlags,DWORD dwBytes)
HeapAlloc equ 4900ECh
; HeapCreate(DWORD flOptions,DWORD dwInitialSize,DWORD dwMaximumSize)
HeapCreate equ 4900ACh
; HeapDestroy(HANDLE hHeap)
HeapDestroy equ 4900B0h
; HeapFree(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem)
HeapFree equ 490100h
; HeapReAlloc(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem,DWORD dwBytes)
HeapReAlloc equ 4900D8h
; HeapSize(HANDLE hHeap,DWORD dwFlags,LPCVOID lpMem)
HeapSize equ 4900D4h
; InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
InitializeCriticalSection equ 49016Ch
; InterlockedDecrement(LPLONG lpAddend)
InterlockedDecrement equ 490200h
; InterlockedIncrement(LPLONG lpAddend)
InterlockedIncrement equ 490118h
; IsBadReadPtr(const void *lp,UINT ucb)
IsBadReadPtr equ 4901BCh
; IsBadWritePtr(LPVOID lp,UINT ucb)
IsBadWritePtr equ 4901CCh
; LCMapStringA(LCID Locale,DWORD dwMapFlags,LPCSTR lpSrcStr,int cchSrc,LPSTR lpDestStr,int cchDest)
LCMapStringA equ 490108h
; LCMapStringW(LCID Locale,DWORD dwMapFlags,LPCWSTR lpSrcStr,int cchSrc,LPWSTR lpDestStr,int cchDest)
LCMapStringW equ 490104h
; LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
LeaveCriticalSection equ 490180h
; LoadLibraryA(LPCSTR lpLibFileName)
LoadLibraryA equ 490178h
; LocalAlloc(UINT uFlags,UINT uBytes)
LocalAlloc equ 490064h
; LocalFree(HLOCAL hMem)
LocalFree equ 4901A8h
; MulDiv(int nNumber,int nNumerator,int nDenominator)
MulDiv equ 4901E8h
; MultiByteToWideChar(UINT CodePage,DWORD dwFlags,LPCSTR lpMultiByteStr,int cchMultiByte,LPWSTR lpWideCharStr,int cchWideChar)
MultiByteToWideChar equ 49010Ch
; RaiseException(DWORD dwExceptionCode,DWORD dwExceptionFlags,DWORD nNumberOfArguments,const DWORD *lpArguments)
RaiseException equ 49006Ch
; ReadFile(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)
ReadFile equ 490198h
; ResetEvent(HANDLE hEvent)
ResetEvent equ 490188h
; SetCommState(HANDLE hFile,LPDCB lpDCB)
SetCommState equ 49019Ch
; SetCommTimeouts(HANDLE hFile,LPCOMMTIMEOUTS lpCommTimeouts)
SetCommTimeouts equ 4901A4h
; SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine,BOOL Add)
SetConsoleCtrlHandler equ 490130h
; SetEndOfFile(HANDLE hFile)
SetEndOfFile equ 49008Ch
; SetEnvironmentVariableA(LPCSTR lpName,LPCSTR lpValue)
SetEnvironmentVariableA equ 490080h
; SetEvent(HANDLE hEvent)
SetEvent equ 49017Ch
; SetFileAttributesA(LPCSTR lpFileName,DWORD dwFileAttributes)
SetFileAttributesA equ 49007Ch
; SetFilePointer(HANDLE hFile,LONG lDistanceToMove,PLONG lpDistanceToMoveHigh,DWORD dwMoveMethod)
SetFilePointer equ 49009Ch
; SetHandleCount(UINT uNumber)
SetHandleCount equ 49005Ch
; SetLastError(DWORD dwErrCode)
SetLastError equ 4900F8h
; SetStdHandle(DWORD nStdHandle,HANDLE hHandle)
SetStdHandle equ 490094h
; SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
SetUnhandledExceptionFilter equ 4901D4h
; Sleep(DWORD dwMilliseconds)
Sleep equ 490168h
; TerminateProcess(HANDLE hProcess,UINT uExitCode)
TerminateProcess equ 4900E8h
; TlsAlloc(void)
TlsAlloc equ 4900FCh
; TlsGetValue(DWORD dwTlsIndex)
TlsGetValue equ 4900F4h
; TlsSetValue(DWORD dwTlsIndex,LPVOID lpTlsValue)
TlsSetValue equ 490124h
; UnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)
UnhandledExceptionFilter equ 4900F0h
; VirtualAlloc(LPVOID lpAddress,DWORD dwSize,DWORD flAllocationType,DWORD flProtect)
VirtualAlloc equ 490098h
; VirtualFree(LPVOID lpAddress,DWORD dwSize,DWORD dwFreeType)
VirtualFree equ 4900A8h
; VirtualQuery(LPCVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,DWORD dwLength)
VirtualQuery equ 4901C4h
; WaitForMultipleObjects(DWORD nCount,const HANDLE *lpHandles,BOOL bWaitAll,DWORD dwMilliseconds)
WaitForMultipleObjects equ 490194h
; WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds)
WaitForSingleObject equ 49018Ch
; WideCharToMultiByte(UINT CodePage,DWORD dwFlags,LPCWSTR lpWideCharStr,int cchWideChar,LPSTR lpMultiByteStr,int cchMultiByte,LPCSTR lpDefaultChar,LPBOOL lpUsedDefaultChar)
WideCharToMultiByte equ 490110h
; WriteFile(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped)
WriteFile equ 4901B8h
; lstrcpynA(LPSTR lpString1,LPCSTR lpString2,int iMaxLength)
lstrcpynA equ 4901C8h