Files
sigmaker-ida/idasdk76/plugins/uunp/win9x.cpp
2021-10-31 21:20:46 +02:00

173 lines
4.3 KiB
C++

/*
This file contains Win9x (95, 98) specific stuff.
It can be safely ignored if you are only interested in XP systems.
*/
#include <windows.h>
#include <ida.hpp>
#include <idp.hpp>
#include <dbg.hpp>
#include "uunp.hpp"
#pragma pack(push, 1)
//lint --e{958} Padding required
struct push_insn_t
{
BYTE push; // must be 0x68
DWORD ea;
};
//lint -estring(958,member) padding is required to align members
struct push_jump_insns_t
{
BYTE push; // must be 0x68
DWORD ea;
BYTE jmp; // must be 0xE9
DWORD reloff; //lint !e754 not referenced
};
#pragma pack(pop)
//--------------------------------------------------------------------------
// find the address of the thunk for GetProcessAddress() under Windows 9x
void uunp_ctx_t::win9x_resolve_gpa_thunk()
{
DWORD off;
ea_t ea = curmod.start_ea + offsetof(IMAGE_DOS_HEADER, e_lfanew);
if ( read_dbg_memory(ea, &off, sizeof(off)) != sizeof(off) )
return;
#define _OI offsetof(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory[ \
IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
if ( read_dbg_memory((DWORD)curmod.start_ea + off + _OI, &off, sizeof(off)) != sizeof(off) )
return;
#undef _OI
IMAGE_IMPORT_DESCRIPTOR imp;
DWORD hK32 = DWORD(size_t(GetModuleHandle("kernel32")));
bool found = false;
for ( off += (DWORD)curmod.start_ea;
read_dbg_memory(off, &imp, sizeof(imp)) == sizeof(imp) && imp.Name;
off += sizeof(imp) )
{
if ( imp.ForwarderChain == hK32 )
{
found = true;
break;
}
}
if ( found )
{
DWORD tmp;
for ( off = imp.FirstThunk + (DWORD)curmod.start_ea;
read_dbg_memory(off, &tmp, sizeof(tmp)) == sizeof(tmp) && tmp != 0;
off += sizeof(DWORD) )
{
if ( tmp >= hK32 )
continue; // for TH_xxx entries
push_insn_t thunk;
if ( read_dbg_memory(tmp, &thunk, sizeof(thunk)) != sizeof(thunk)
|| thunk.push != 0x68 )
{
break;
}
if ( thunk.ea == bp_gpa )
{
bp_gpa = tmp;
break;
}
}
}
}
//--------------------------------------------------------------------------
// find all dwords equal to 'ea' and remember their translations
// search in the current module
static bool calc_thunk_target(uunp_ctx_t &ctx, uint32 ea32, uint32 imp32)
{
bool matched = false;
for ( ea_t pos = ctx.curmod.start_ea;
pos <= ctx.curmod.end_ea;
pos += sizeof(DWORD) )
{
pos = bin_search2(pos, ctx.curmod.end_ea, (uchar *)&ea32, NULL,
4, BIN_SEARCH_NOBREAK|BIN_SEARCH_CASE|BIN_SEARCH_FORWARD);
if ( pos == BADADDR )
break;
if ( pos & 3 )
continue;
flags_t F = get_flags(pos);
if ( is_tail(F) )
continue;
matched = true;
ctx.thunks[pos] = imp32;
}
return matched;
}
//--------------------------------------------------------------------------
// find Windows 9x import thunk
static bool resolve_thunk(uunp_ctx_t &ctx, ea_t ea)
{
push_jump_insns_t thunk;
if ( get_bytes(&thunk, sizeof(thunk), ea) != sizeof(thunk)
|| thunk.push != 0x68 || thunk.jmp != 0xE9
|| thunk.ea < 0x80000000 || thunk.ea >= 0xC0000000 )
{
return false;
}
if ( !calc_thunk_target(ctx, uint32(ea), thunk.ea) )
msg("%a: Thunked import (%08a) without references\n", ea, ea_t(thunk.ea));
return true;
}
//--------------------------------------------------------------------------
// Windows 9x: find thunked imports and their targets
void uunp_ctx_t::find_thunked_imports()
{
if ( (DWORD)bp_gpa & 0xF )
{
warning("Non-standard thunk address");
return;
}
// find the thunk area for our module
invalidate_dbgmem_contents(curmod.start_ea, curmod.end_ea); // for bin-search
invalidate_dbgmem_contents(0x80000000, 0xC0000000);
for ( ea_t ea = bp_gpa; ea > 0x80000000; ea -= 0x10 )
{
if ( !resolve_thunk(*this, ea) )
break;
}
for ( ea_t ea = bp_gpa + 0x10; ea < 0xC0000000; ea += 0x10 )
{
if ( !resolve_thunk(*this, ea) )
break;
}
if ( thunks.empty() )
warning("Could not find thunk area");
}
//--------------------------------------------------------------------------
ea_t uunp_ctx_t::win9x_find_thunk(ea_t ea)
{
thunks_t::iterator p = thunks.find(ea);
ea_t func = p != thunks.end() ? p->second : get_dword(ea);
return func;
}