1
0
mirror of https://github.com/DxWnd/DxWnd.reloaded synced 2024-12-30 09:25:35 +01:00
DxWnd.reloaded/dll/iatpatch.cpp

479 lines
16 KiB
C++
Raw Permalink Normal View History

#include <windows.h>
#include "dxwnd.h"
#include "dxwcore.hpp"
void *IATPatchDefault(HMODULE module, DWORD ordinal, char *dll, void *apiproc, const char *apiname, void *hookproc)
{
PIMAGE_NT_HEADERS pnth;
PIMAGE_IMPORT_DESCRIPTOR pidesc;
DWORD base, rva;
PSTR impmodule;
PIMAGE_THUNK_DATA ptaddr;
PIMAGE_THUNK_DATA ptname;
PIMAGE_IMPORT_BY_NAME piname;
DWORD oldprotect;
void *org;
OutTraceH("IATPatch: module=%x ordinal=%x name=%s dll=%s\n", module, ordinal, apiname, dll);
base = (DWORD)module;
org = 0; // by default, ret = 0 => API not found
__try{
pnth = PIMAGE_NT_HEADERS(PBYTE(base) + PIMAGE_DOS_HEADER(base)->e_lfanew);
if(!pnth) {
OutTraceH("IATPatch: ERROR no PNTH at %d\n", __LINE__);
return 0;
}
rva = pnth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if(!rva) {
OutTraceH("IATPatch: ERROR no RVA at %d\n", __LINE__);
return 0;
}
pidesc = (PIMAGE_IMPORT_DESCRIPTOR)(base + rva);
while(pidesc->FirstThunk){
impmodule = (PSTR)(base + pidesc->Name);
//OutTraceH("IATPatch: analyze impmodule=%s\n", impmodule);
char *fname = impmodule;
for(; *fname; fname++); for(; !*fname; fname++);
if(!lstrcmpi(dll, impmodule)) {
OutTraceH("IATPatch: dll=%s found at %x\n", dll, impmodule);
ptaddr = (PIMAGE_THUNK_DATA)(base + (DWORD)pidesc->FirstThunk);
ptname = (pidesc->OriginalFirstThunk) ? (PIMAGE_THUNK_DATA)(base + (DWORD)pidesc->OriginalFirstThunk) : NULL;
while(ptaddr->u1.Function){
// OutTraceH("IATPatch: address=%x ptname=%x\n", ptaddr->u1.AddressOfData, ptname);
if (ptname){
// examining by function name
if(!IMAGE_SNAP_BY_ORDINAL(ptname->u1.Ordinal)){
piname = (PIMAGE_IMPORT_BY_NAME)(base + (DWORD)ptname->u1.AddressOfData);
OutTraceH("IATPatch: BYNAME ordinal=%x address=%x name=%s hint=%x\n", ptaddr->u1.Ordinal, ptaddr->u1.AddressOfData, (char *)piname->Name, piname->Hint);
if(!lstrcmpi(apiname, (char *)piname->Name)) break;
}
else{
// OutTraceH("IATPatch: BYORD target=%x ord=%x\n", ordinal, IMAGE_ORDINAL32(ptname->u1.Ordinal));
if(ordinal && (IMAGE_ORDINAL32(ptname->u1.Ordinal) == ordinal)) { // skip unknow ordinal 0
OutTraceH("IATPatch: BYORD ordinal=%x addr=%x\n", ptname->u1.Ordinal, ptaddr->u1.Function);
//OutTraceH("IATPatch: BYORD GetProcAddress=%x\n", GetProcAddress(GetModuleHandle(dll), MAKEINTRESOURCE(IMAGE_ORDINAL32(ptname->u1.Ordinal))));
break;
}
}
}
else {
// OutTraceH("IATPatch: fname=%s\n", fname);
if(!lstrcmpi(apiname, fname)) {
OutTraceH("IATPatch: BYSCAN ordinal=%x address=%x name=%s\n", ptaddr->u1.Ordinal, ptaddr->u1.AddressOfData, fname);
break;
}
for(; *fname; fname++); for(; !*fname; fname++);
}
if (apiproc){
// examining by function addr
if(ptaddr->u1.Function == (DWORD)apiproc) break;
}
ptaddr ++;
if (ptname) ptname ++;
}
if(ptaddr->u1.Function) {
org = (void *)ptaddr->u1.Function;
if(org == hookproc) return 0; // already hooked
if(!VirtualProtect(&ptaddr->u1.Function, 4, PAGE_EXECUTE_READWRITE, &oldprotect)) {
OutTraceDW("IATPatch: VirtualProtect error %d at %d\n", GetLastError(), __LINE__);
return 0;
}
ptaddr->u1.Function = (DWORD)hookproc;
if(!VirtualProtect(&ptaddr->u1.Function, 4, oldprotect, &oldprotect)) {
OutTraceDW("IATPatch: VirtualProtect error %d at %d\n", GetLastError(), __LINE__);
return 0;
}
if (!FlushInstructionCache(GetCurrentProcess(), &ptaddr->u1.Function, 4)) {
OutTraceDW("IATPatch: FlushInstructionCache error %d at %d\n", GetLastError(), __LINE__);
return 0;
}
OutTraceH("IATPatch hook=%s address=%x->%x\n", apiname, org, hookproc);
return org;
}
}
pidesc ++;
}
if(!pidesc->FirstThunk) {
OutTraceH("IATPatch: PE unreferenced function %s:%s\n", dll, apiname);
return 0;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
OutTraceH("IATPatch: EXCEPTION hook=%s:%s Hook Failed.\n", dll, apiname);
}
return org;
}
void *IATPatchSequential(HMODULE module, DWORD ordinal, char *dll, void *apiproc, const char *apiname, void *hookproc)
{
PIMAGE_NT_HEADERS pnth;
PIMAGE_IMPORT_DESCRIPTOR pidesc;
DWORD base, rva;
PSTR impmodule;
PIMAGE_THUNK_DATA ptaddr;
PIMAGE_THUNK_DATA ptname;
PIMAGE_IMPORT_BY_NAME piname;
DWORD oldprotect;
void *org;
OutTraceH("IATPatch: module=%x ordinal=%x name=%s dll=%s\n", module, ordinal, apiname, dll);
base = (DWORD)module;
org = 0; // by default, ret = 0 => API not found
__try{
pnth = PIMAGE_NT_HEADERS(PBYTE(base) + PIMAGE_DOS_HEADER(base)->e_lfanew);
if(!pnth) {
OutTraceH("IATPatch: ERROR no PNTH at %d\n", __LINE__);
return 0;
}
rva = pnth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if(!rva) {
OutTraceH("IATPatch: ERROR no RVA at %d\n", __LINE__);
return 0;
}
pidesc = (PIMAGE_IMPORT_DESCRIPTOR)(base + rva);
// move fname pointer to first API name
char *fname;
while(pidesc->FirstThunk){
impmodule = (PSTR)(base + pidesc->Name);
fname = impmodule;
for(; *fname; fname++); for(; !*fname; fname++);
pidesc ++;
}
pidesc = (PIMAGE_IMPORT_DESCRIPTOR)(base + rva);
//OutTraceB("IATPatch: first call=%s\n", fname);
while(pidesc->FirstThunk){
impmodule = (PSTR)(base + pidesc->Name);
if(!lstrcmpi(dll, impmodule)) {
OutTraceH("IATPatch: dll=%s found at %x\n", dll, impmodule);
//OutTraceH("IATPatch: first call=%s\n", fname);
ptaddr = (PIMAGE_THUNK_DATA)(base + (DWORD)pidesc->FirstThunk);
ptname = (pidesc->OriginalFirstThunk) ? (PIMAGE_THUNK_DATA)(base + (DWORD)pidesc->OriginalFirstThunk) : NULL;
while(ptaddr->u1.Function){
// OutTraceH("IATPatch: address=%x ptname=%x\n", ptaddr->u1.AddressOfData, ptname);
if (ptname){
// examining by function name
if(!IMAGE_SNAP_BY_ORDINAL(ptname->u1.Ordinal)){
piname = (PIMAGE_IMPORT_BY_NAME)(base + (DWORD)ptname->u1.AddressOfData);
OutTraceH("IATPatch: BYNAME ordinal=%x address=%x name=%s hint=%x\n", ptaddr->u1.Ordinal, ptaddr->u1.AddressOfData, (char *)piname->Name, piname->Hint);
if(!lstrcmpi(apiname, (char *)piname->Name)) break;
}
else{
// OutTraceH("IATPatch: BYORD target=%x ord=%x\n", ordinal, IMAGE_ORDINAL32(ptname->u1.Ordinal));
if(ordinal && (IMAGE_ORDINAL32(ptname->u1.Ordinal) == ordinal)) { // skip unknow ordinal 0
OutTraceH("IATPatch: BYORD ordinal=%x addr=%x\n", ptname->u1.Ordinal, ptaddr->u1.Function);
//OutTraceH("IATPatch: BYORD GetProcAddress=%x\n", GetProcAddress(GetModuleHandle(dll), MAKEINTRESOURCE(IMAGE_ORDINAL32(ptname->u1.Ordinal))));
break;
}
}
}
else {
// OutTraceH("IATPatch: fname=%s\n", fname);
if(!lstrcmpi(apiname, fname)) {
OutTraceH("IATPatch: BYSCAN ordinal=%x address=%x name=%s\n", ptaddr->u1.Ordinal, ptaddr->u1.AddressOfData, fname);
break;
}
for(; *fname; fname++); for(; !*fname; fname++);
}
if (apiproc){
// examining by function addr
if(ptaddr->u1.Function == (DWORD)apiproc) break;
}
ptaddr ++;
if (ptname) ptname ++;
}
if(ptaddr->u1.Function) {
OutTraceDW("IATPatch: hooking %s\n", apiname);
org = (void *)ptaddr->u1.Function;
if(org == hookproc) return 0; // already hooked
if(!VirtualProtect(&ptaddr->u1.Function, 4, PAGE_EXECUTE_READWRITE, &oldprotect)) {
OutTraceDW("IATPatch: VirtualProtect error %d at %d\n", GetLastError(), __LINE__);
return 0;
}
ptaddr->u1.Function = (DWORD)hookproc;
if(!VirtualProtect(&ptaddr->u1.Function, 4, oldprotect, &oldprotect)) {
OutTraceDW("IATPatch: VirtualProtect error %d at %d\n", GetLastError(), __LINE__);
return 0;
}
if (!FlushInstructionCache(GetCurrentProcess(), &ptaddr->u1.Function, 4)) {
OutTraceDW("IATPatch: FlushInstructionCache error %d at %d\n", GetLastError(), __LINE__);
return 0;
}
OutTraceH("IATPatch hook=%s address=%x->%x\n", apiname, org, hookproc);
return org;
}
}
else{
//OutTraceDW("IATPatch: skip dll=%s first call=%s\n", impmodule, fname);
// skip dll fnames ...
ptaddr = (PIMAGE_THUNK_DATA)(base + (DWORD)pidesc->FirstThunk);
//ptname = (pidesc->OriginalFirstThunk) ? (PIMAGE_THUNK_DATA)(base + (DWORD)pidesc->OriginalFirstThunk) : NULL;
while(ptaddr->u1.Function){
ptaddr ++;
for(; *fname; fname++); for(; !*fname; fname++);
}
}
pidesc ++;
}
if(!pidesc->FirstThunk) {
OutTraceH("IATPatch: PE unreferenced function %s:%s\n", dll, apiname);
return 0;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
OutTraceH("IATPatch: EXCEPTION hook=%s:%s Hook Failed.\n", dll, apiname);
}
return org;
}
// Note: when pidesc->OriginalFirstThunk is NULL, the pidesc->FirstThunk points to an array of
// RVA for imported function names in the PE file, but when the loader loads the program these
// values gets replaced by the function addresses. The only way to retrieve the function names
// after that event is to point to the dll name and get the list of the following strings sequentially
// taking in account that the function names have variable length and are aligned to a DWORD
// boundary, so that a practical way to retrieve the next name is this piece of code:
// for(; *fname; fname++); for(; !*fname; fname++);
// Note (2): the above condition is not always true. The original version of "Al Unser Jr Arcade Racing"
// executable ALUNSER.EXE seems to have all dll names first, then followed by the names of all the dll
// entries, so that it is still possible to retrieve the function name, but a different schema must be used.
void DumpImportTableDefault(HMODULE module)
{
PIMAGE_NT_HEADERS pnth;
PIMAGE_IMPORT_DESCRIPTOR pidesc;
DWORD base, rva;
PSTR impmodule;
PIMAGE_THUNK_DATA ptaddr;
PIMAGE_THUNK_DATA ptname;
PIMAGE_IMPORT_BY_NAME piname;
base=(DWORD)module;
// OutTrace("DumpImportTable: base=%x\n", base);
__try{
pnth = PIMAGE_NT_HEADERS(PBYTE(base) + PIMAGE_DOS_HEADER(base)->e_lfanew);
if(!pnth) {
OutTrace("DumpImportTable: ERROR no pnth at %d\n", __LINE__);
return;
}
rva = pnth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if(!rva) {
OutTrace("DumpImportTable: ERROR no rva at %d\n", __LINE__);
return;
}
pidesc = (PIMAGE_IMPORT_DESCRIPTOR)(base + rva);
while(pidesc->FirstThunk){
char *fname;
impmodule = (PSTR)(base + pidesc->Name);
OutTrace("DumpImportTable: ENTRY timestamp=%x module=%s forwarderchain=%x\n",
pidesc->TimeDateStamp, impmodule, pidesc->ForwarderChain);
if(pidesc->OriginalFirstThunk) {
ptname = (PIMAGE_THUNK_DATA)(base + (DWORD)pidesc->OriginalFirstThunk);
}
else{
ptname = 0;
fname = impmodule;
for(; *fname; fname++); for(; !*fname; fname++);
OutTrace("DumpImportTable: no PE OFTs - stripped module=%s\n", impmodule);
}
ptaddr = (PIMAGE_THUNK_DATA)(base + (DWORD)pidesc->FirstThunk);
while(ptaddr->u1.Function){
OutTrace("addr=%x", ptaddr->u1.Function);
ptaddr ++;
if(ptname){
if(!IMAGE_SNAP_BY_ORDINAL(ptname->u1.Ordinal)){
piname = (PIMAGE_IMPORT_BY_NAME)(base + (DWORD)ptname->u1.AddressOfData);
OutTrace(" hint=%x name=%s", piname->Hint, piname->Name);
ptname ++;
}
}
else {
OutTrace(" name=%s", fname);
for(; *fname; fname++); for(; !*fname; fname++);
}
OutTrace("\n");
}
OutTrace("*** EOT ***\n", ptaddr->u1.Function);
pidesc ++;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
OutTraceDW("DumpImportTable: EXCEPTION\n");
}
return;
}
void DumpImportTableSequential(HMODULE module)
{
PIMAGE_NT_HEADERS pnth;
PIMAGE_IMPORT_DESCRIPTOR pidesc;
DWORD base, rva;
PSTR impmodule;
PIMAGE_THUNK_DATA ptaddr;
PIMAGE_THUNK_DATA ptname;
PIMAGE_IMPORT_BY_NAME piname;
base=(DWORD)module;
// OutTrace("DumpImportTable: base=%x\n", base);
__try{
pnth = PIMAGE_NT_HEADERS(PBYTE(base) + PIMAGE_DOS_HEADER(base)->e_lfanew);
if(!pnth) {
OutTrace("DumpImportTable: ERROR no pnth at %d\n", __LINE__);
return;
}
rva = pnth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if(!rva) {
OutTrace("DumpImportTable: ERROR no rva at %d\n", __LINE__);
return;
}
pidesc = (PIMAGE_IMPORT_DESCRIPTOR)(base + rva);
OutTrace("DumpImportTable: pidesc=%x\n", pidesc);
char *fname;
PIMAGE_IMPORT_DESCRIPTOR savepidesc = pidesc;
while(pidesc->FirstThunk){
impmodule = (PSTR)(base + pidesc->Name);
fname = impmodule;
for(; *fname; fname++); for(; !*fname; fname++);
pidesc ++;
}
pidesc = savepidesc;
OutTrace("DumpImportTable: no PE OFTs - first call=%s\n", fname);
while(pidesc->FirstThunk){
//char *fname;
impmodule = (PSTR)(base + pidesc->Name);
OutTrace("DumpImportTable: ENTRY timestamp=%x module=%s forwarderchain=%x\n",
pidesc->TimeDateStamp, impmodule, pidesc->ForwarderChain);
if(pidesc->OriginalFirstThunk) {
ptname = (PIMAGE_THUNK_DATA)(base + (DWORD)pidesc->OriginalFirstThunk);
}
else{
ptname = 0;
//fname = impmodule;
//for(; *fname; fname++); for(; !*fname; fname++);
OutTrace("DumpImportTable: no PE OFTs - stripped module=%s\n", impmodule);
}
ptaddr = (PIMAGE_THUNK_DATA)(base + (DWORD)pidesc->FirstThunk);
while(ptaddr->u1.Function){
OutTrace("addr=%x", ptaddr->u1.Function);
ptaddr ++;
if(ptname){
if(!IMAGE_SNAP_BY_ORDINAL(ptname->u1.Ordinal)){
piname = (PIMAGE_IMPORT_BY_NAME)(base + (DWORD)ptname->u1.AddressOfData);
OutTrace(" hint=%x name=%s", piname->Hint, piname->Name);
ptname ++;
}
}
else {
OutTrace(" name=%s", fname);
for(; *fname; fname++); for(; !*fname; fname++);
}
OutTrace("\n");
}
OutTrace("*** EOT ***\n", ptaddr->u1.Function);
pidesc ++;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
OutTraceDW("DumpImportTable: EXCEPTION\n");
}
return;
}
static char* stristr(char* str1, const char* str2)
{
char* p1 = str1 ;
const char* p2 = str2 ;
char* r = *p2 == 0 ? str1 : 0 ;
while(*p1 != 0 && *p2 != 0) {
if(tolower(*p1) == tolower(*p2)){
if(r == 0) r = p1;
p2++ ;
}
else {
p2 = str2;
if(tolower(*p1) == tolower(*p2)){
r = p1;
p2++ ;
}
else{
r = 0;
}
}
p1++ ;
}
return *p2 == 0 ? r : 0 ;
}
BOOL IsIATSequential(HMODULE module)
{
PIMAGE_NT_HEADERS pnth;
PIMAGE_IMPORT_DESCRIPTOR pidesc;
DWORD base, rva;
base=(DWORD)module;
__try{
pnth = PIMAGE_NT_HEADERS(PBYTE(base) + PIMAGE_DOS_HEADER(base)->e_lfanew);
if(!pnth) {
OutTrace("IsIATSequential: ERROR no pnth at %d\n", __LINE__);
return FALSE;
}
rva = pnth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if(!rva) {
OutTrace("IsIATSequential: ERROR no rva at %d\n", __LINE__);
return FALSE;
}
pidesc = (PIMAGE_IMPORT_DESCRIPTOR)(base + rva);
//OutTrace("IsIATSequential: pidesc=%x\n", pidesc);
char *fname = (PSTR)(base + pidesc->Name);
// first string should be a DLL in both cases
if(!stristr(fname, ".DLL")) {
OutTrace("IsIATSequential: ERROR no .DLL at %d\n", __LINE__);
return FALSE;
}
// skip first string
for(; *fname; fname++); for(; !*fname; fname++);
// if second string is another DLL it is sequential, otherwise not.
//OutTraceB("IsIATSequential: second entry=%s\n", fname);
return (BOOL)stristr(fname, ".DLL");
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
OutTraceDW("IsIATSequential: EXCEPTION\n");
}
return FALSE;
}