2024-05-06 23:30:27 +08:00
|
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
|
|
|
|
|
|
namespace { // unnamed
|
|
|
|
|
|
|
|
|
|
// jichi 4/19/2014: Return the integer that can mask the signature
|
|
|
|
|
// Artikash 8/4/2018: change implementation
|
|
|
|
|
DWORD SigMask(DWORD sig)
|
|
|
|
|
{
|
|
|
|
|
DWORD count = 0;
|
|
|
|
|
while (sig)
|
|
|
|
|
{
|
|
|
|
|
sig >>= 8;
|
|
|
|
|
++count;
|
|
|
|
|
}
|
|
|
|
|
count -= 4;
|
|
|
|
|
count = -count;
|
|
|
|
|
return 0xffffffff >> (count << 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t SafeSearchMemory(uint64_t startAddr, uint64_t endAddr, const BYTE* bytes, short length)
|
|
|
|
|
{
|
|
|
|
|
__try
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < endAddr - startAddr - length; ++i)
|
|
|
|
|
for (int j = 0; j <= length; ++j)
|
|
|
|
|
if (j == length) return startAddr + i; // not sure about this algorithm...
|
|
|
|
|
else if (*((BYTE*)startAddr + i + j) != *(bytes + j) && *(bytes + j) != XX) break;
|
|
|
|
|
}
|
|
|
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
|
{
|
|
|
|
|
ConsoleOutput("SearchMemory ERROR");
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace unnamed
|
|
|
|
|
|
|
|
|
|
namespace Util
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
#ifndef _WIN64
|
|
|
|
|
// jichi 8/24/2013: binary search?
|
|
|
|
|
DWORD 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 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 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 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 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 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 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 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;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
bool CheckFile(LPCWSTR name)
|
|
|
|
|
{
|
|
|
|
|
WIN32_FIND_DATAW unused;
|
|
|
|
|
HANDLE file = FindFirstFileW(name, &unused);
|
|
|
|
|
if (file != INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
FindClose(file);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
wchar_t path[MAX_PATH * 2];
|
|
|
|
|
wchar_t* end = path + GetModuleFileNameW(nullptr, path, MAX_PATH);
|
|
|
|
|
while (*(--end) != L'\\');
|
|
|
|
|
wcscpy_s(end + 1, MAX_PATH, name);
|
|
|
|
|
file = FindFirstFileW(path, &unused);
|
|
|
|
|
if (file != INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
FindClose(file);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Search string in rsrc section. This section usually contains version and copyright info.
|
|
|
|
|
bool SearchResourceString(LPCWSTR str)
|
|
|
|
|
{
|
|
|
|
|
uintptr_t hModule = (uintptr_t)GetModuleHandleW(nullptr);
|
|
|
|
|
IMAGE_DOS_HEADER *DosHdr;
|
|
|
|
|
IMAGE_NT_HEADERS *NtHdr;
|
|
|
|
|
DosHdr = (IMAGE_DOS_HEADER *)hModule;
|
|
|
|
|
uintptr_t rsrc, size;
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-04 13:30:31 +08:00
|
|
|
|
std::pair<uintptr_t, uintptr_t> QueryModuleLimits(HMODULE module,uintptr_t addition,DWORD protect)
|
2024-02-07 20:59:24 +08:00
|
|
|
|
{
|
|
|
|
|
uintptr_t moduleStartAddress = (uintptr_t)module + addition;
|
|
|
|
|
uintptr_t moduleStopAddress = moduleStartAddress;
|
|
|
|
|
MEMORY_BASIC_INFORMATION info;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
VirtualQuery((void*)moduleStopAddress, &info, sizeof(info));
|
|
|
|
|
moduleStopAddress = (uintptr_t)info.BaseAddress + info.RegionSize;
|
|
|
|
|
} while (info.Protect>=protect);
|
|
|
|
|
moduleStopAddress -= info.RegionSize;
|
|
|
|
|
return { moduleStartAddress, moduleStopAddress };
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-04 13:30:31 +08:00
|
|
|
|
std::vector<uintptr_t> SearchMemory(const void* bytes, short length, DWORD protect, uintptr_t minAddr, uintptr_t maxAddr)
|
2024-02-07 20:59:24 +08:00
|
|
|
|
{
|
|
|
|
|
SYSTEM_INFO systemInfo;
|
|
|
|
|
GetNativeSystemInfo(&systemInfo);
|
2024-03-04 13:30:31 +08:00
|
|
|
|
std::vector<std::pair<uintptr_t, uintptr_t>> validMemory;
|
2024-02-07 20:59:24 +08:00
|
|
|
|
for (BYTE* probe = NULL; probe < systemInfo.lpMaximumApplicationAddress;)
|
|
|
|
|
{
|
|
|
|
|
MEMORY_BASIC_INFORMATION info = {};
|
|
|
|
|
if (!VirtualQuery(probe, &info, sizeof(info)))
|
|
|
|
|
{
|
|
|
|
|
probe += systemInfo.dwPageSize;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-03-04 13:30:31 +08:00
|
|
|
|
if ((uintptr_t)info.BaseAddress + info.RegionSize >= minAddr && info.Protect >= protect && !(info.Protect & PAGE_GUARD))
|
|
|
|
|
validMemory.push_back({ (uintptr_t)info.BaseAddress, info.RegionSize });
|
2024-02-07 20:59:24 +08:00
|
|
|
|
probe += info.RegionSize;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-04 13:30:31 +08:00
|
|
|
|
std::vector<uintptr_t> ret;
|
2024-02-07 20:59:24 +08:00
|
|
|
|
for (auto memory : validMemory)
|
2024-03-04 13:30:31 +08:00
|
|
|
|
for (uintptr_t addr = max(memory.first, minAddr); true;)
|
2024-02-07 20:59:24 +08:00
|
|
|
|
if (addr < maxAddr && (addr = SafeSearchMemory(addr, memory.first + memory.second, (const BYTE*)bytes, length)))
|
|
|
|
|
ret.push_back(addr++);
|
|
|
|
|
else break;
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uintptr_t FindFunction(const char* function)
|
|
|
|
|
{
|
|
|
|
|
static HMODULE modules[300] = {};
|
|
|
|
|
static auto _ = EnumProcessModules(GetCurrentProcess(), modules, sizeof(modules), DUMMY);
|
|
|
|
|
for (auto module : modules) if (auto addr = GetProcAddress(module, function)) return (uintptr_t)addr;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-26 23:14:04 +08:00
|
|
|
|
uintptr_t SafeFindEnclosingAlignedFunction(uintptr_t addr, uintptr_t range)
|
2024-02-07 20:59:24 +08:00
|
|
|
|
{
|
2024-03-26 23:14:04 +08:00
|
|
|
|
uintptr_t r = 0;
|
2024-02-07 20:59:24 +08:00
|
|
|
|
__try{
|
|
|
|
|
r = MemDbg::findEnclosingAlignedFunction(addr, range); // this function might raise if failed
|
|
|
|
|
}__except(EXCEPTION_EXECUTE_HANDLER) {}
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-26 23:14:04 +08:00
|
|
|
|
uintptr_t SafeFindBytes(LPCVOID pattern, size_t patternSize, uintptr_t lowerBound, uintptr_t upperBound)
|
2024-02-07 20:59:24 +08:00
|
|
|
|
{
|
|
|
|
|
ULONG r = 0;
|
|
|
|
|
__try{
|
|
|
|
|
r = MemDbg::findBytes(pattern, patternSize, lowerBound, upperBound);
|
|
|
|
|
}__except(EXCEPTION_EXECUTE_HANDLER) {}
|
|
|
|
|
return r;
|
|
|
|
|
}
|
2024-03-26 23:14:04 +08:00
|
|
|
|
#ifndef _WIN64
|
|
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
|
// jichi 7/17/2014: Search mapped memory for emulators
|
|
|
|
|
ULONG _SafeMatchBytesInMappedMemory(LPCVOID pattern, DWORD patternSize, BYTE wildcard,
|
|
|
|
|
ULONG start, ULONG stop, ULONG step)
|
|
|
|
|
{
|
|
|
|
|
for (ULONG i = start; i < stop; i += step) // + patternSize to avoid overlap
|
|
|
|
|
if (ULONG r = SafeFindBytes(pattern, patternSize, i, i + step + patternSize + 1))
|
|
|
|
|
return r;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
ULONG SafeMatchBytesInGCMemory(LPCVOID pattern, DWORD patternSize)
|
|
|
|
|
{
|
|
|
|
|
enum : ULONG {
|
|
|
|
|
start = MemDbg::MappedMemoryStartAddress // 0x01000000
|
|
|
|
|
, stop = MemDbg::MemoryStopAddress // 0x7ffeffff
|
|
|
|
|
, step = start
|
|
|
|
|
};
|
|
|
|
|
return _SafeMatchBytesInMappedMemory(pattern, patternSize, XX, start, stop, step);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _WIN64
|
|
|
|
|
|
|
|
|
|
std::vector<DWORD> findrelativecall(const BYTE* pattern ,int length,DWORD calladdress,DWORD start, DWORD end)
|
|
|
|
|
{
|
|
|
|
|
std::vector<DWORD> save;
|
|
|
|
|
for (; start < end;start+=1 ) {
|
|
|
|
|
DWORD addr=MemDbg::findBytes(pattern, length, start, end);
|
|
|
|
|
start = addr;
|
|
|
|
|
if (!addr)return save;
|
|
|
|
|
|
|
|
|
|
BYTE callop = 0xE8;
|
|
|
|
|
|
|
|
|
|
union little {
|
|
|
|
|
DWORD _dw;
|
|
|
|
|
BYTE _bytes[4];
|
|
|
|
|
}relative;
|
|
|
|
|
relative._dw = (calladdress - addr -length- 5);
|
|
|
|
|
DWORD calladdr = addr + length;
|
|
|
|
|
if (*((BYTE*)calladdr) == callop) {
|
|
|
|
|
|
|
|
|
|
calladdr += 1;
|
|
|
|
|
BYTE* _b = (BYTE*)calladdr;
|
|
|
|
|
BYTE* _a = relative._bytes;
|
|
|
|
|
/*ConsoleOutput("%p", addr);
|
|
|
|
|
ConsoleOutput("%p %x", calladdress, relative._dw);
|
|
|
|
|
ConsoleOutput("%02x%02x%02x%02x %02x%02x%02x%02x", _a[0], _a[1], _a[2], _a[3], _b[0], _b[1], _b[2], _b[3]);*/
|
|
|
|
|
if ((_a[0] == _b[0]) && (_a[1] == _b[1]) && (_a[2] == _b[2]) && (_a[3] == _b[3])) {
|
|
|
|
|
save.push_back(start);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return save;
|
|
|
|
|
}
|
|
|
|
|
std::vector<DWORD> findxref_reverse_checkcallop(DWORD addr, DWORD from, DWORD to,BYTE op) {
|
|
|
|
|
//op可以为E8 call E9 jump
|
|
|
|
|
//上面的版本其实就应该checkcallop的,之前忘了,但不敢乱改破坏之前的了,不然还要重新测试。
|
|
|
|
|
std::vector<DWORD> res;
|
|
|
|
|
if (addr == 0)return res;
|
|
|
|
|
DWORD now = to;
|
|
|
|
|
while (now > from) {
|
|
|
|
|
DWORD calladdr = now - 5;
|
|
|
|
|
if(IsBadReadPtr((LPVOID)(calladdr + 1),4)==0){
|
|
|
|
|
DWORD relative = *(DWORD*)(calladdr + 1);
|
|
|
|
|
if (now + relative == addr) {
|
|
|
|
|
if(*(BYTE*)calladdr==op)
|
|
|
|
|
res.push_back(calladdr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
now -= 1;
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
uintptr_t finddllfunctioncall(uintptr_t funcptr,uintptr_t start, uintptr_t end,WORD sig,bool reverse){
|
|
|
|
|
auto entry=Util::FindImportEntry(start,funcptr);
|
|
|
|
|
if(entry==0)return 0;
|
|
|
|
|
BYTE bytes[]={0xFF,0x15,XX4};
|
|
|
|
|
memcpy(bytes+2,&entry,4);
|
|
|
|
|
memcpy(bytes,&sig,2);
|
|
|
|
|
if(reverse)
|
|
|
|
|
return reverseFindBytes(bytes,sizeof(bytes),start,end);
|
|
|
|
|
else
|
|
|
|
|
return MemDbg::findBytes(bytes,sizeof(bytes),start,end);
|
|
|
|
|
}
|
|
|
|
|
uintptr_t findfuncstart(uintptr_t addr,uintptr_t range){
|
|
|
|
|
const BYTE funcstart[] = {
|
|
|
|
|
0x55,0x8b,0xec
|
|
|
|
|
};
|
|
|
|
|
addr = reverseFindBytes(funcstart, sizeof(funcstart), addr-range, addr);
|
|
|
|
|
return addr;
|
|
|
|
|
}
|
2024-04-25 18:09:46 +08:00
|
|
|
|
#define buildbytes(ret) auto entry=Util::FindImportEntry(hmodule,addr); \
|
|
|
|
|
if(entry==0)return ret;\
|
|
|
|
|
BYTE bytes[]={XX,XX,XX4};\
|
|
|
|
|
if(movreg){\
|
|
|
|
|
bytes[0]=0x8b,bytes[1]=movreg;\
|
|
|
|
|
}\
|
|
|
|
|
else{\
|
|
|
|
|
bytes[0]=0xff;bytes[1]=0x15;\
|
|
|
|
|
}\
|
|
|
|
|
memcpy(bytes+2,&entry,4);
|
|
|
|
|
uintptr_t findiatcallormov(uintptr_t addr,DWORD hmodule, uintptr_t start, uintptr_t end,bool reverse,BYTE movreg){
|
|
|
|
|
buildbytes(0)
|
|
|
|
|
if(reverse)
|
|
|
|
|
return reverseFindBytes(bytes, sizeof(bytes), start, end);
|
|
|
|
|
else
|
|
|
|
|
return MemDbg::findBytes(bytes, sizeof(bytes), start, end);
|
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
|
|
2024-04-25 18:09:46 +08:00
|
|
|
|
std::vector<uintptr_t> findiatcallormov_all(uintptr_t addr, DWORD hmodule,uintptr_t start, uintptr_t end,DWORD protect,BYTE movreg){
|
|
|
|
|
buildbytes({})
|
|
|
|
|
return Util::SearchMemory(bytes, sizeof(bytes), protect, start, end);
|
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
2024-03-26 23:14:04 +08:00
|
|
|
|
uintptr_t reverseFindBytes(const BYTE* pattern, int length, uintptr_t start, uintptr_t end,int offset,bool checkalign) {
|
2024-02-07 20:59:24 +08:00
|
|
|
|
for (end -= length; end >= start; end -= 1) {
|
|
|
|
|
bool success=true;
|
|
|
|
|
for(int i=0;i<length;i++){
|
|
|
|
|
if(pattern[i]!=*(BYTE*)(end+i) && pattern[i]!=XX){
|
|
|
|
|
success=false;break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-26 23:14:04 +08:00
|
|
|
|
if(success)
|
|
|
|
|
{
|
|
|
|
|
auto ret=end+offset;
|
|
|
|
|
|
|
|
|
|
if(checkalign && ret&0xf)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
|
// if (memcmp(pattern, (const BYTE*)(end), length) == 0) {
|
|
|
|
|
// return end;
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
std::vector<uintptr_t> findxref_reverse(uintptr_t addr, uintptr_t from, uintptr_t to) {
|
|
|
|
|
std::vector<uintptr_t> res;
|
|
|
|
|
if (addr == 0)return res;
|
|
|
|
|
uintptr_t now = to;
|
|
|
|
|
while (now > from) {
|
|
|
|
|
uintptr_t calladdr = now - 5;
|
|
|
|
|
uintptr_t relative = *(int*)(calladdr + 1);
|
|
|
|
|
if (now + relative == addr) {
|
|
|
|
|
res.push_back(calladdr);
|
|
|
|
|
}
|
|
|
|
|
now -= 1;
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
int hexCharToValue(char c) {
|
|
|
|
|
if (c >= '0' && c <= '9') {
|
|
|
|
|
return c - '0';
|
|
|
|
|
} else if (c >= 'A' && c <= 'F') {
|
|
|
|
|
return c - 'A' + 10;
|
|
|
|
|
} else if (c >= 'a' && c <= 'f') {
|
|
|
|
|
return c - 'a' + 10;
|
|
|
|
|
} else if(c=='?'){
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
uintptr_t find_pattern(const char* pattern,uintptr_t start,uintptr_t end){
|
|
|
|
|
std::vector<int> check;
|
|
|
|
|
bool ignore=false;
|
|
|
|
|
for(int i=0;i<strlen(pattern);i++){
|
|
|
|
|
auto c=pattern[i];
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case '\n':
|
|
|
|
|
ignore=false; //注释,直到换行
|
|
|
|
|
case ' ': //忽略空格,制表,回车
|
|
|
|
|
case '\t':
|
|
|
|
|
break;
|
|
|
|
|
case '/': //注释
|
|
|
|
|
ignore=true;
|
|
|
|
|
break;
|
|
|
|
|
default:{ //? 0-9A-Fa-f
|
|
|
|
|
auto _i=hexCharToValue(c);
|
|
|
|
|
if(_i==-2)return 0;
|
|
|
|
|
check.push_back(_i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(check.size()%2!=0)return 0;
|
|
|
|
|
std::vector<BYTE>_type,_pattern;
|
|
|
|
|
for(int j=0;j<check.size();j+=2){
|
|
|
|
|
if(check[j]!=-1&&check[j+1]!=-1){
|
|
|
|
|
_type.push_back(0);
|
|
|
|
|
_pattern.push_back(check[j]*0x10+check[j+1]);
|
|
|
|
|
}
|
|
|
|
|
else if(check[j]==-1&&check[j+1]==-1){ //??
|
|
|
|
|
_type.push_back(1);
|
|
|
|
|
_pattern.push_back(0);
|
|
|
|
|
}
|
|
|
|
|
else if(check[j]==-1){ //?_
|
|
|
|
|
_type.push_back(2);
|
|
|
|
|
_pattern.push_back(check[j+1]);
|
|
|
|
|
}
|
|
|
|
|
else{// _?
|
|
|
|
|
_type.push_back(3);
|
|
|
|
|
_pattern.push_back(check[j]*0x10);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(uintptr_t i=start;i<end;i++){
|
|
|
|
|
bool succ=true;
|
|
|
|
|
for(int j=0;succ&&(j<_pattern.size());j+=1){
|
|
|
|
|
switch (_type[j])
|
|
|
|
|
{
|
|
|
|
|
case 0:{
|
|
|
|
|
if(_pattern[j]!=*(BYTE*)(i+j)){
|
|
|
|
|
succ=false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 1:{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 2:{
|
|
|
|
|
if(((*(BYTE*)(i+j))&0xf)!=_pattern[j]){
|
|
|
|
|
succ=false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 3:{
|
|
|
|
|
if(((*(BYTE*)(i+j))&0xf0)!=_pattern[j]){
|
|
|
|
|
succ=false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(succ)
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Engine::isAddressReadable(const uintptr_t *p)
|
|
|
|
|
{ return p && !::IsBadReadPtr(p, sizeof(*p)); }
|
|
|
|
|
|
|
|
|
|
bool Engine::isAddressReadable(const char *p, size_t count)
|
|
|
|
|
{ return p && count && !::IsBadReadPtr(p, sizeof(*p) * count); }
|
|
|
|
|
|
|
|
|
|
bool Engine::isAddressReadable(const wchar_t *p, size_t count)
|
|
|
|
|
{ return p && count && !::IsBadReadPtr(p, sizeof(*p) * count); }
|
|
|
|
|
|
|
|
|
|
bool Engine::isAddressWritable(const uintptr_t *p)
|
|
|
|
|
{ return p && !::IsBadWritePtr((LPVOID)p, sizeof(*p)); }
|
|
|
|
|
|
|
|
|
|
bool Engine::isAddressWritable(const char *p, size_t count)
|
|
|
|
|
{ return p && count && !::IsBadWritePtr((LPVOID)p, sizeof(*p) * count); }
|
|
|
|
|
|
|
|
|
|
bool Engine::isAddressWritable(const wchar_t *p, size_t count)
|
2024-03-21 17:57:04 +08:00
|
|
|
|
{ return p && count && !::IsBadWritePtr((LPVOID)p, sizeof(*p) * count); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace{
|
|
|
|
|
|
2024-03-31 19:00:26 +08:00
|
|
|
|
uint32_t *Xstrcpy(uint32_t *s, const uint32_t *r){
|
|
|
|
|
while(*r){
|
|
|
|
|
*s=*r;
|
|
|
|
|
s+=1;
|
|
|
|
|
r+=1;
|
|
|
|
|
}
|
|
|
|
|
*s=0;
|
|
|
|
|
return s;
|
|
|
|
|
}
|
2024-03-21 17:57:04 +08:00
|
|
|
|
wchar_t *Xstrcpy(wchar_t *s, const wchar_t *r){return wcscpy(s,r);}
|
|
|
|
|
char *Xstrcpy(char *s, const char *r){return strcpy(s,r);}
|
|
|
|
|
template<class CharT>
|
|
|
|
|
void write_string_new_impl(uintptr_t* data, size_t* len,const std::basic_string<CharT>& s){
|
|
|
|
|
CharT* _data=new CharT[s.size()+1];
|
|
|
|
|
Xstrcpy(_data,s.c_str());
|
|
|
|
|
*data=(uintptr_t)_data;
|
|
|
|
|
if(len)
|
|
|
|
|
*len=s.size()*sizeof(CharT);
|
|
|
|
|
}
|
|
|
|
|
template<class CharT>
|
|
|
|
|
bool write_string_overwrite_impl(void* data, size_t* len,const std::basic_string<CharT>& s){
|
|
|
|
|
Xstrcpy((CharT*)data,s.c_str());
|
|
|
|
|
*len=s.size()*sizeof(CharT);
|
|
|
|
|
return s.size();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void write_string_new(uintptr_t* data, size_t* len,const std::wstring& s){write_string_new_impl<wchar_t>(data,len,s);}
|
|
|
|
|
void write_string_new(uintptr_t* data, size_t* len,const std::string& s){write_string_new_impl<char>(data,len,s);}
|
|
|
|
|
|
2024-03-31 19:00:26 +08:00
|
|
|
|
bool write_string_overwrite(void* data, size_t* len,const std::basic_string<uint32_t>& s){return write_string_overwrite_impl<uint32_t>(data,len,s);}
|
2024-03-21 17:57:04 +08:00
|
|
|
|
bool write_string_overwrite(void* data, size_t* len,const std::wstring& s){return write_string_overwrite_impl<wchar_t>(data,len,s);}
|
2024-03-22 14:23:39 +08:00
|
|
|
|
bool write_string_overwrite(void* data, size_t* len,const std::string& s){return write_string_overwrite_impl<char>(data,len,s);}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
|
|
|
|
|
std::vector<WindowInfo>* windowList = reinterpret_cast<std::vector<WindowInfo>*>(lParam);
|
|
|
|
|
DWORD processId;
|
|
|
|
|
GetWindowThreadProcessId(hwnd, &processId);
|
|
|
|
|
if (processId == GetCurrentProcessId()) {
|
|
|
|
|
auto length=GetWindowTextLengthW(hwnd);
|
|
|
|
|
auto title=std::vector<WCHAR>(length+1);
|
|
|
|
|
GetWindowTextW(hwnd, title.data(), title.size());
|
|
|
|
|
|
|
|
|
|
WindowInfo windowInfo;
|
|
|
|
|
windowInfo.handle = hwnd;
|
|
|
|
|
windowInfo.title = title.data();
|
|
|
|
|
|
|
|
|
|
windowList->push_back(windowInfo);
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
std::vector<WindowInfo>get_proc_windows(){
|
|
|
|
|
std::vector<WindowInfo> windows;
|
|
|
|
|
EnumWindows(EnumWindowsProc, reinterpret_cast<LPARAM>(&windows));
|
|
|
|
|
return windows;
|
2024-04-25 18:09:46 +08:00
|
|
|
|
}
|