forked from Public-Mirror/Textractor
306 lines
7.6 KiB
C++
306 lines
7.6 KiB
C++
// util/util.cc
|
|
// 8/23/2013 jichi
|
|
// Branch: ITH_Engine/engine.cpp, revision 133
|
|
// See: http://ja.wikipedia.org/wiki/プロジェクト:美少女ゲーム系/ゲームエンジン
|
|
|
|
#include "engine/util.h"
|
|
#include "ith/sys/sys.h"
|
|
|
|
namespace { // unnamed
|
|
|
|
// jichi 4/19/2014: Return the integer that can mask the signature
|
|
DWORD SigMask(DWORD sig)
|
|
{
|
|
__asm
|
|
{
|
|
xor ecx,ecx
|
|
mov eax,sig
|
|
_mask:
|
|
shr eax,8
|
|
inc ecx
|
|
test eax,eax
|
|
jnz _mask
|
|
sub ecx,4
|
|
neg ecx
|
|
or eax,-1
|
|
shl ecx,3
|
|
shr eax,cl
|
|
}
|
|
}
|
|
|
|
} // namespace unnamed
|
|
|
|
// jichi 8/24/2013: binary search?
|
|
DWORD Util::GetCodeRange(DWORD hModule,DWORD *low, DWORD *high)
|
|
{
|
|
IMAGE_DOS_HEADER *DosHdr;
|
|
IMAGE_NT_HEADERS *NtHdr;
|
|
DWORD dwReadAddr;
|
|
IMAGE_SECTION_HEADER *shdr;
|
|
DosHdr = (IMAGE_DOS_HEADER *)hModule;
|
|
if (IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {
|
|
dwReadAddr = hModule + DosHdr->e_lfanew;
|
|
NtHdr = (IMAGE_NT_HEADERS *)dwReadAddr;
|
|
if (IMAGE_NT_SIGNATURE == NtHdr->Signature) {
|
|
shdr = (PIMAGE_SECTION_HEADER)((DWORD)(&NtHdr->OptionalHeader) + NtHdr->FileHeader.SizeOfOptionalHeader);
|
|
while ((shdr->Characteristics & IMAGE_SCN_CNT_CODE) == 0)
|
|
shdr++;
|
|
*low = hModule + shdr->VirtualAddress;
|
|
*high = *low + (shdr->Misc.VirtualSize & 0xfffff000) + 0x1000;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
DWORD Util::FindCallAndEntryBoth(DWORD fun, DWORD size, DWORD pt, DWORD sig)
|
|
{
|
|
//WCHAR str[0x40];
|
|
enum { reverse_length = 0x800 };
|
|
DWORD t, l;
|
|
DWORD mask = SigMask(sig);
|
|
bool flag2;
|
|
for (DWORD i = 0x1000; i < size-4; i++) {
|
|
bool flag1 = false;
|
|
if (*(BYTE *)(pt + i) == 0xe8) {
|
|
flag1 = flag2 = true;
|
|
t = *(DWORD *)(pt + i + 1);
|
|
} else if (*(WORD *)(pt + i) == 0x15ff) {
|
|
flag1 = true;
|
|
flag2 = false;
|
|
t = *(DWORD *)(pt + i + 2);
|
|
}
|
|
if (flag1) {
|
|
if (flag2) {
|
|
flag1 = (pt + i + 5 + t == fun);
|
|
l = 5;
|
|
} else if (t >= pt && t <= pt + size - 4) {
|
|
flag1 = fun == *(DWORD *)t;
|
|
l = 6;
|
|
} else
|
|
flag1 = false;
|
|
if (flag1)
|
|
//swprintf(str,L"CALL addr: 0x%.8X",pt + i);
|
|
//OutputConsole(str);
|
|
for (DWORD j = i; j > i - reverse_length; j--)
|
|
if ((*(WORD *)(pt + j)) == (sig & mask)) //Fun entry 1.
|
|
//swprintf(str,L"Entry: 0x%.8X",pt + j);
|
|
//OutputConsole(str);
|
|
return pt + j;
|
|
else
|
|
i += l;
|
|
}
|
|
}
|
|
//OutputConsole(L"Find call and entry failed.");
|
|
return 0;
|
|
}
|
|
|
|
DWORD Util::FindCallOrJmpRel(DWORD fun, DWORD size, DWORD pt, bool jmp)
|
|
{
|
|
BYTE sig = (jmp) ? 0xe9 : 0xe8;
|
|
for (DWORD i = 0x1000; i < size - 4; i++)
|
|
if (sig == *(BYTE *)(pt + i)) {
|
|
DWORD t = *(DWORD *)(pt + i + 1);
|
|
if(fun == pt + i + 5 + t)
|
|
//OutputDWORD(pt + i);
|
|
return pt + i;
|
|
else
|
|
i += 5;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
DWORD Util::FindCallOrJmpAbs(DWORD fun, DWORD size, DWORD pt, bool jmp)
|
|
{
|
|
WORD sig = jmp ? 0x25ff : 0x15ff;
|
|
for (DWORD i = 0x1000; i < size - 4; i++)
|
|
if (sig == *(WORD *)(pt + i)) {
|
|
DWORD t = *(DWORD *)(pt + i + 2);
|
|
if (t > pt && t < pt + size) {
|
|
if (fun == *(DWORD *)t)
|
|
return pt + i;
|
|
else
|
|
i += 5;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
DWORD Util::FindCallBoth(DWORD fun, DWORD size, DWORD pt)
|
|
{
|
|
for (DWORD i = 0x1000; i < size - 4; i++) {
|
|
if (*(BYTE *)(pt + i) == 0xe8) {
|
|
DWORD t = *(DWORD *)(pt + i + 1) + pt + i + 5;
|
|
if (t == fun)
|
|
return i;
|
|
}
|
|
if (*(WORD *)(pt + i) == 0x15ff) {
|
|
DWORD t = *(DWORD *)(pt + i + 2);
|
|
if (t >= pt && t <= pt + size - 4) {
|
|
if (*(DWORD *)t == fun)
|
|
return i;
|
|
else
|
|
i += 6;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
DWORD Util::FindCallAndEntryAbs(DWORD fun, DWORD size, DWORD pt, DWORD sig)
|
|
{
|
|
//WCHAR str[0x40];
|
|
enum { reverse_length = 0x800 };
|
|
DWORD mask = SigMask(sig);
|
|
for (DWORD i = 0x1000; i < size - 4; i++)
|
|
if (*(WORD *)(pt + i) == 0x15ff) {
|
|
DWORD t = *(DWORD *)(pt + i + 2);
|
|
if (t >= pt && t <= pt + size - 4) {
|
|
if (*(DWORD *)t == fun)
|
|
//swprintf(str,L"CALL addr: 0x%.8X",pt + i);
|
|
//OutputConsole(str);
|
|
for (DWORD j = i ; j > i - reverse_length; j--)
|
|
if ((*(DWORD *)(pt + j) & mask) == sig) // Fun entry 1.
|
|
//swprintf(str,L"Entry: 0x%.8X",pt + j);
|
|
//OutputConsole(str);
|
|
return pt + j;
|
|
|
|
} else
|
|
i += 6;
|
|
}
|
|
//OutputConsole(L"Find call and entry failed.");
|
|
return 0;
|
|
}
|
|
|
|
DWORD Util::FindCallAndEntryRel(DWORD fun, DWORD size, DWORD pt, DWORD sig)
|
|
{
|
|
//WCHAR str[0x40];
|
|
enum { reverse_length = 0x800 };
|
|
if (DWORD i = FindCallOrJmpRel(fun, size, pt, false)) {
|
|
DWORD mask = SigMask(sig);
|
|
for (DWORD j = i; j > i - reverse_length; j--)
|
|
if (((*(DWORD *)j) & mask) == sig) //Fun entry 1.
|
|
//swprintf(str,L"Entry: 0x%.8X",j);
|
|
//OutputConsole(str);
|
|
return j;
|
|
//OutputConsole(L"Find call and entry failed.");
|
|
}
|
|
return 0;
|
|
}
|
|
DWORD Util::FindEntryAligned(DWORD start, DWORD back_range)
|
|
{
|
|
start &= ~0xf;
|
|
for (DWORD i = start, j = start - back_range; i > j; i-=0x10) {
|
|
DWORD k = *(DWORD *)(i-4);
|
|
if (k == 0xcccccccc
|
|
|| k == 0x90909090
|
|
|| k == 0xccccccc3
|
|
|| k == 0x909090c3
|
|
)
|
|
return i;
|
|
DWORD t = k & 0xff0000ff;
|
|
if (t == 0xcc0000c2 || t == 0x900000c2)
|
|
return i;
|
|
k >>= 8;
|
|
if (k == 0xccccc3 || k == 0x9090c3)
|
|
return i;
|
|
t = k & 0xff;
|
|
if (t == 0xc2)
|
|
return i;
|
|
k >>= 8;
|
|
if (k == 0xccc3 || k == 0x90c3)
|
|
return i;
|
|
k >>= 8;
|
|
if (k == 0xc3)
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
DWORD Util::FindImportEntry(DWORD hModule, DWORD fun)
|
|
{
|
|
IMAGE_DOS_HEADER *DosHdr;
|
|
IMAGE_NT_HEADERS *NtHdr;
|
|
DWORD IAT, end, pt, addr;
|
|
DosHdr = (IMAGE_DOS_HEADER *)hModule;
|
|
if (IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {
|
|
NtHdr = (IMAGE_NT_HEADERS *)(hModule + DosHdr->e_lfanew);
|
|
if (IMAGE_NT_SIGNATURE == NtHdr->Signature) {
|
|
IAT = NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress;
|
|
end = NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size;
|
|
IAT += hModule;
|
|
end += IAT;
|
|
for (pt = IAT; pt < end; pt += 4) {
|
|
addr = *(DWORD *)pt;
|
|
if (addr == fun)
|
|
return pt;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Search string in rsrc section. This section usually contains version and copyright info.
|
|
bool Util::SearchResourceString(LPCWSTR str)
|
|
{
|
|
DWORD hModule = Util::GetModuleBase();
|
|
IMAGE_DOS_HEADER *DosHdr;
|
|
IMAGE_NT_HEADERS *NtHdr;
|
|
DosHdr = (IMAGE_DOS_HEADER *)hModule;
|
|
DWORD rsrc, size;
|
|
//__asm int 3
|
|
if (IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {
|
|
NtHdr = (IMAGE_NT_HEADERS *)(hModule + DosHdr->e_lfanew);
|
|
if (IMAGE_NT_SIGNATURE == NtHdr->Signature) {
|
|
rsrc = NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
|
|
if (rsrc) {
|
|
rsrc += hModule;
|
|
if (IthGetMemoryRange((LPVOID)rsrc, &rsrc ,&size) &&
|
|
SearchPattern(rsrc, size - 4, str, wcslen(str) << 1))
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// jichi 4/15/2014: Copied from GetModuleBase in ITH CLI, for debugging purpose
|
|
DWORD Util::FindModuleBase(DWORD hash)
|
|
{
|
|
__asm
|
|
{
|
|
mov eax,fs:[0x30]
|
|
mov eax,[eax+0xc]
|
|
mov esi,[eax+0x14]
|
|
mov edi,_wcslwr
|
|
listfind:
|
|
mov edx,[esi+0x28]
|
|
test edx,edx
|
|
jz notfound
|
|
push edx
|
|
call edi
|
|
pop edx
|
|
xor eax,eax
|
|
calc:
|
|
movzx ecx, word ptr [edx]
|
|
test cl,cl
|
|
jz fin
|
|
ror eax,7
|
|
add eax,ecx
|
|
add edx,2
|
|
jmp calc
|
|
fin:
|
|
cmp eax,[hash]
|
|
je found
|
|
mov esi,[esi]
|
|
jmp listfind
|
|
notfound:
|
|
xor eax,eax
|
|
jmp termin
|
|
found:
|
|
mov eax,[esi+0x10]
|
|
termin:
|
|
}
|
|
}
|
|
|
|
// EOF
|