diff options
Diffstat (limited to 'ext/detours/samples/disas/disas.cpp')
-rw-r--r-- | ext/detours/samples/disas/disas.cpp | 702 |
1 files changed, 702 insertions, 0 deletions
diff --git a/ext/detours/samples/disas/disas.cpp b/ext/detours/samples/disas/disas.cpp new file mode 100644 index 0000000..db8ef6a --- /dev/null +++ b/ext/detours/samples/disas/disas.cpp @@ -0,0 +1,702 @@ +///////////////////////////////////////////////////////////////////////////// +// +// Module: disas.cpp (disas.exe - Detours Test Program) +// +// Microsoft Research Detours Package +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +#define DETOURS_INTERNAL +#include <detours.h> +#include <stdio.h> +#include <stdlib.h> + +///////////////////////////////////////////////////////////////////////// ARM. +// +#ifdef DETOURS_ARM + +extern "C" BYTE TestCodes[]; + +void DumpMemoryFragment(PBYTE pbData, ULONG cbData, ULONG cbSpace) +{ + ULONG n = 0; + if (cbData >= 4) { + printf("%04x%04x ", ((PUSHORT)pbData)[0], ((PUSHORT)pbData)[1]); + n += 4; + } + else if (cbData >= 2) { + printf("%04x ", *((PUSHORT)pbData)); + n += 2; + } + + for (; n < cbSpace; n++) { + if (n < cbData) { + printf("%02x", pbData[n]); + } + else { + printf(" "); + } + } + if (n < cbData) { + printf("."); + } + else { + printf(" "); + } +} + +inline ULONG fetch_thumb_opcode(PBYTE pbCode) +{ + ULONG Opcode = *(UINT16 *)&pbCode[0]; + if (Opcode >= 0xe800) { + Opcode = (Opcode << 16) | *(UINT16 *)&pbCode[2]; + } + return Opcode; +} + +BOOL IsTerminate(PBYTE pbSrc) +{ + ULONG opcode = fetch_thumb_opcode(pbSrc); + + if ((opcode & 0xff87) == 0x4700) { + // bx r + return TRUE; + } + +#if 0 + if ((opcode & 0xfbf08f00) == 0xf2400c00) { // movw r12,#xxxx + return TRUE; + } + + if ((opcode == 0xf8dcf000) { // ldr pc,[r12] + ULONG Immediate = ((opcode2 << 12) & 0xf7000000) | + ((opcode2 << 1) & 0x08000000) | + ((opcode2 << 16) & 0x00ff0000) | + ((opcode >> 4) & 0x0000f700) | + ((opcode >> 15) & 0x00000800) | + ((opcode >> 0) & 0x000000ff); + PBYTE pbTarget = *(PBYTE *)Immediate; + if (detour_is_imported(pbCode, pbTarget)) { + PBYTE pbNew = *(PBYTE *)pbTarget; + DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); + return pbNew; + } + } + } + } +#endif + + return FALSE; +} + +#endif // DETOURS_ARM + +///////////////////////////////////////////////////////////////// X86 and X64. +// +#if defined(DETOURS_X86) || defined(DETOURS_X64) + +extern "C" BYTE TestCodes[]; + +void DumpMemoryFragment(PBYTE pbData, ULONG cbData, ULONG cbSpace) +{ + ULONG n = 0; + for (; n < cbSpace; n++) { + if (n < cbData) { + printf("%02x", pbData[n]); + } + else { + printf(" "); + } + } + if (n < cbData) { + printf("."); + } + else { + printf(" "); + } +} + +BOOL IsTerminate(PBYTE pbSrc) +{ + if ((0xC3 == pbSrc[0] && 0x00 == pbSrc[1]) || // bx lr + 0xCB == pbSrc[0] || // RETF + 0xC2 == pbSrc[0] || // RET dw + 0xCA == pbSrc[0] || // RETF dw + 0xEB == pbSrc[0] || // JMP ob + 0xE9 == pbSrc[0] || // JMP ol + 0xEA == pbSrc[0]) { // JMP ol + + return TRUE; + } + if (0xff == pbSrc[0] && 0x25 == pbSrc[1]) // JMP [addr] + return TRUE; + return FALSE; +} + +#endif // DETOURS_X86 || DETOURS_X64 + +/////////////////////////////////////////////////////////// X86, X64, and ARM. +// +#if defined(DETOURS_X86) || defined(DETOURS_X64) || defined(DETOURS_ARM) +struct BasicBlockLink +{ + public: + BasicBlockLink * m_pNext; + PBYTE m_pbEntry; + PCHAR m_pszName; + + public: + BasicBlockLink(PBYTE pbEntry, PCHAR pszName = NULL) + { + m_pNext = NULL; + m_pbEntry = pbEntry; + m_pszName = pszName; + + *s_ppTail = this; + s_ppTail = &m_pNext; + } + + BasicBlockLink * Next() + { + return m_pNext; + } + + static BasicBlockLink * GetListHead() + { + return s_pHead; + } + + protected: + static BasicBlockLink * s_pHead; + static BasicBlockLink ** s_ppTail; +}; + +BasicBlockLink * BasicBlockLink::s_pHead = NULL; +BasicBlockLink ** BasicBlockLink::s_ppTail = &BasicBlockLink::s_pHead; + +static PBYTE s_pbBegin = NULL; +static PBYTE s_pbLimit = NULL; + +int TestDetourCopyInstruction(PBYTE pbSrcInstruction, PCHAR pszFunction) +{ + PBYTE pbSrc = pbSrcInstruction; + ULONG nIns = 0; + + if (pszFunction) { + printf("%s:\n", pszFunction); + } + for (; nIns < 4096; nIns++) { + BYTE rbDst[128]; + PVOID pbDstPool = (PVOID)(rbDst + sizeof(rbDst)); + LONG lExtra = 0; + PVOID pbTarget = NULL; + ULONG cbStep = (ULONG)((PBYTE)DetourCopyInstruction(rbDst, &pbDstPool, pbSrc, + &pbTarget, &lExtra) - pbSrc); + + printf(" %p:", pbSrc); + DumpMemoryFragment(rbDst, cbStep, 10); + printf(" "); + DumpMemoryFragment(rbDst, cbStep, 10); + if (pbTarget) { + if (pbTarget == DETOUR_INSTRUCTION_TARGET_DYNAMIC) { + printf(" Dynamic\n"); + } + else { + printf(" %p%c\n", pbTarget, + (pbTarget >= s_pbBegin && pbTarget < s_pbLimit) ? ' ' : '!'); + } + } + else { + printf("\n"); + } + + if (pbTarget && pbTarget != DETOUR_INSTRUCTION_TARGET_DYNAMIC) { + if (pbTarget > pbSrc && + pbTarget >= s_pbBegin && + pbTarget < s_pbLimit + ) { + (void) new BasicBlockLink((PBYTE)pbTarget, NULL); + } + } + + if (IsTerminate(pbSrc)) { + break; + } + + pbSrc += cbStep; + } + return nIns; +} + +BOOL CALLBACK ExportCallback(_In_opt_ PVOID pContext, + _In_ ULONG nOrdinal, + _In_opt_ LPCSTR pszName, + _In_opt_ PVOID pCode) +{ + (void)pContext; + (void)nOrdinal; + (void)pCode; + + (VOID) new BasicBlockLink((PBYTE)pCode, pszName ? pszName : "[NO NAME]"); + return TRUE; +} +#endif // DETOURS_X86 || DETOURS_X64 + +//////////////////////////////////////////////////////////////////////// IA64. +// +#ifdef DETOURS_IA64 +#pragma warning(disable: 4201) // ignore warning about unnamed sturcture in union. + +void DumpHi(PBYTE pbData, ULONG cbData, ULONG cbSpace) +{ + ULONG n = 0; + for (; n < cbSpace; n++) { + if (n < cbData) { + printf("%02x", pbData[(cbData - 1) - n]); + } + else { + printf(" "); + } + } + printf("\n"); +} + +struct DETOUR_IA64_BUNDLE_DISASSEMBLE : public DETOUR_IA64_BUNDLE +{ + public: + void SetBrx(UINT64 raw) + { + SetBrl(); + SetBrlImm(raw); + } + + void Dis() + { + const char szUnitNames[17] = "?aimbflx?AIMBFLX"; + + printf("%p: ", data); + BYTE nTemplate = GetTemplate(); + BYTE nInst0 = GetInst0(); + BYTE nInst1 = GetInst1(); + BYTE nInst2 = GetInst2(); + BYTE nUnit0 = GetUnit0(); + BYTE nUnit1 = GetUnit1(); + BYTE nUnit2 = GetUnit2(); + if (nUnit1 == L_UNIT) { // MLX instruction + UINT64 d2 = ( + // 0x0000000000fffff0 + ((wide[1] & 0x00fffff000000000) >> 32) | + // 0x000000ffff000000 + ((wide[0] & 0xffff000000000000) >> 24) | + // 0x7fffff0000000000 + ((wide[1] & 0x00000000007fffff) << 40) | + // 0x8000000000000000 + ((wide[1] & 0x0800000000000000) << 4) + ); + printf("%02x %c%01x %010I64lx %c%01x %016I64lx", + nTemplate, + szUnitNames[nUnit0], nInst0, GetData0(), + szUnitNames[nUnit2], nInst2, d2); + } + else { + printf("%02x %c%01x %010I64lx %c%01x %010I64lx %c%01x %010I64lx", + nTemplate, + szUnitNames[nUnit0], nInst0, GetData0(), + szUnitNames[nUnit1], nInst1, GetData1(), + szUnitNames[nUnit2], nInst2, GetData2()); + } + + if (IsBrl()) { + printf(" brl %p", GetBrlTarget()); + } + else if (IsMovlGp()) { + printf(" movl gp=%p", GetMovlGp()); + } + if ((wide[0] & 0xfffffc000603ffff) == 0x002024000200100b && + wide[1] == 0x0004000000203008) { + + ULONG64 offset = + ((wide[0] & 0x0000000001fc0000) >> 18) | // imm7b + ((wide[0] & 0x000001ff00000000) >> 25) | // imm9d + ((wide[0] & 0x00000000f8000000) >> 11); // imm5c + if (wide[0] & 0x0000020000000000) { + offset |= 0xffffffffffe00000; + } + printf(" imm=%016I64lx", offset); + } + printf("\n"); + } +}; + +////////////////////////////////////////////////////////////////////////////// +// +BOOL CALLBACK ExportCallbackIA64(_In_opt_ PVOID pContext, + _In_ ULONG nOrdinal, + _In_opt_ LPCSTR pszName, + _In_opt_ PVOID pCode) +{ + (void)pContext; + (void)nOrdinal; + + DETOUR_IA64_BUNDLE_DISASSEMBLE *pb = *(DETOUR_IA64_BUNDLE_DISASSEMBLE **)pCode; + DETOUR_IA64_BUNDLE temp; + + if (!pb[0].Copy(&temp)) { + printf("%s:\n ", pszName ? pszName : "[NO NAME]"); + pb[0].Dis(); + } + return TRUE; +} + +#if 0 +void TestBoth() +{ + LPVOID pvBase = VirtualAlloc((PBYTE)0x800000000, 0x10000, + MEM_RESERVE | MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + + DETOUR_IA64_BUNDLE *pbBase = (DETOUR_IA64_BUNDLE *)pvBase; + DETOUR_IA64_BUNDLE *pb = pbBase; + + printf("TestBoth:\n"); + for (UINT64 i = 0x10; i < 0x8000000000000000; i <<= 1) { + pb->SetMovlGp(i); + if (pb->GetMovlGp() != i) { + printf("Error in MovlGp!\n"); + return; + } + pb++; + + pb->SetBrl(i); + if (pb->GetBrlEip() != i) { + printf("Error in Brl!\n"); + return; + } + pb++; + } + + for (UINT64 i = (UINT64)(INT64)-0x10; i > 0; i <<= 1) { + pb->SetMovlGp(i); + if (pb->GetMovlGp() != i) { + printf("Error in MovlGp!\n"); + return; + } + pb++; + + pb->SetBrl(i); + if (pb->GetBrlEip() != i) { + printf("Error in Brl!\n"); + return; + } + pb++; + } + + printf("u %p %p\n", pbBase, pb); +} +#endif +#endif // DETOURS_IA64 + +int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR lpszCmdLine, int nCmdShow) +{ + (void)hprev; + (void)hinst; + (void)lpszCmdLine; + (void)nCmdShow; +
+ // Bug report, but it works here.
+ // 07ff8`4b783054 49ba 70b3d93a d40fb998 mov r10,98B90FD43AD9B370h
+ //
+ {
+ static const UCHAR mov_r10_imm64[] = {0x49, 0xba, 1, 2, 3, 4, 5, 6, 7, 8 };
+
+ PVOID const after = DetourCopyInstructionX64(0, 0, const_cast<PUCHAR>(mov_r10_imm64), 0, 0);
+
+ if (after != &mov_r10_imm64 + 1)
+ {
+ printf("mov_r10_imm64 failed, expected:%p vs. got:%p\n", &mov_r10_imm64 + 1, after);
+ if (IsDebuggerPresent())
+ {
+ __debugbreak();
+ DetourCopyInstructionX64(0, 0, const_cast<PUCHAR>(mov_r10_imm64), 0, 0);
+ }
+ return 1;
+ }
+ }
+ +#ifdef DETOURS_IA64 + // First we check the pre-canned TestCodes from disasm.asm + // + PBYTE pbTest = *(PBYTE*)WinMain; + for (;; pbTest += 16) { + DETOUR_IA64_BUNDLE_DISASSEMBLE *pb = (DETOUR_IA64_BUNDLE_DISASSEMBLE *)pbTest; + + pb->Dis(); + if (pbTest[0] == 0xff) { + break; + } + DumpHi(pbTest, 16, 16); + } + +#if 0 + printf("\n\n"); + + DETOUR_IA64_BUNDLE_DISASSEMBLE *pb = (DETOUR_IA64_BUNDLE_DISASSEMBLE *)pbTest; + DETOUR_IA64_BUNDLE_DISASSEMBLE *pbBeg = pb; + DWORD dwOld; + VirtualProtect(pb, 0x2000, PAGE_EXECUTE_READWRITE, &dwOld); + printf("%p: (%d)\n", pb, sizeof(pb)); + pb++; + printf("%p: (%d)\n", pb, sizeof(pb)); + pb++; pb->SetBrx(0); + pb++; pb->SetBrx(0); + pb++; pb->SetBrx(0); + pb++; pb->SetBrx(0xffffffffffffffff); + pb++; pb->SetBrx(0x0fffffffffffffff); + pb++; pb->SetBrx(0x00ffffffffffffff); + pb++; pb->SetBrx(0x000fffffffffffff); + pb++; pb->SetBrx(0x0000ffffffffffff); + pb++; pb->SetBrx(0x00000fffffffffff); + pb++; pb->SetBrx(0x000000ffffffffff); + pb++; pb->SetBrx(0x0000000fffffffff); + pb++; pb->SetBrx(0x00000000ffffffff); + pb++; pb->SetBrx(0x000000000fffffff); + pb++; pb->SetBrx(0x0000000000ffffff); + pb++; pb->SetBrx(0x00000000000fffff); + pb++; pb->SetBrx(0x000000000000ffff); + pb++; pb->SetBrx(0x0000000000000fff); + pb++; pb->SetBrx(0x00000000000000ff); + pb++; pb->SetBrx(0x000000000000000f); + pb++; pb->SetBrx(0x0000000000000000); + pb++; pb->SetBrx(0xffffffffffffffff); + pb++; pb->SetBrx(0xffffffffffffffff); + pb->SetInst0(0xff); + pb->SetData0(0xffffffffffffffff); + printf("%p:\n", pb); + DETOUR_IA64_BUNDLE_DISASSEMBLE *pbEnd = pb; + for (pb = pbBeg; pb < pbEnd; pb++) { + printf(" %p: ", pb); + DumpHi((BYTE*)pb, 16, 16); + } +#endif + +#if 1 + { + // Then we check all of the code we can find in user32.dll + // + printf("\n"); + HINSTANCE hInst = LoadLibraryA("user32.dll"); + printf("Loaded: user32.dll: %p\n", hInst); + + PBYTE pbEntry = (PBYTE)DetourGetEntryPoint(hInst); + printf("Entry: %p\n", pbEntry); + ExportCallbackIA64(NULL, 0, "[Entry]", pbEntry); + DetourEnumerateExports(hInst, NULL, ExportCallbackIA64); + } + + { + // Then we check all of the code we can find in opengl32.dll + // + printf("\n"); + HINSTANCE hInst = LoadLibraryA("opengl32.dll"); + printf("Loaded: opengl32.dll: %p\n", hInst); + + PBYTE pbEntry = (PBYTE)DetourGetEntryPoint(hInst); + printf("Entry: %p\n", pbEntry); + ExportCallbackIA64(NULL, 0, "[Entry]", pbEntry); + DetourEnumerateExports(hInst, NULL, ExportCallbackIA64); + } + + printf("\n"); + for (HINSTANCE hInst = NULL; (hInst = DetourEnumerateModules(hInst)) != NULL;) { + CHAR szModuleName[512]; + GetModuleFileNameA(hInst, szModuleName, + sizeof(szModuleName)/sizeof(szModuleName[0])); + printf("%p : %s\n", hInst, szModuleName); + DetourEnumerateExports(hInst, NULL, ExportCallbackIA64); + } + + printf("\n"); +#endif +#if 0 + TestBoth(); +#endif +#endif // DETOURS_IA64 + +#if defined(DETOURS_X64) || defined(DETOURS_X86) + // First we check the pre-canned TestCodes from disasm.asm + // + PBYTE pbBegin = (PBYTE)DetourCodeFromPointer(TestCodes, NULL); + printf("%p:\n", pbBegin); + for (PBYTE pbTest = pbBegin;;) { + if (pbTest[0] != 0xcc) { // int 3 + printf("%08lx ", (ULONG)(pbTest - pbBegin)); + DumpMemoryFragment(pbTest, 8, 8); + printf("\n"); + printf("failed on last.\n"); + return 1; + } + pbTest++; + + if (pbTest[0] == 0x70 || pbTest[0] == 0x71) { + printf("[%p]:\n", pbTest); + } + BYTE rbDst[128]; + PVOID pbDstPool = (PVOID)(rbDst + sizeof(rbDst)); + LONG lExtra = 0; + PVOID pbTarget = NULL; + PBYTE pbNext = (PBYTE)DetourCopyInstruction(rbDst, &pbDstPool, pbTest, + &pbTarget, &lExtra); + + LONG cbTest = (LONG)(pbNext - pbTest); + + printf("%08lx ", (ULONG)(pbTest - pbBegin)); + DumpMemoryFragment(pbTest, cbTest, 12); + printf("[%16p] ", pbTarget); + DumpMemoryFragment(rbDst, cbTest + lExtra, 11); + printf("\n"); + + if (pbTest[cbTest] != 0xcc) { + printf("failed!\n"); + return 1; + } + + pbTest += cbTest; + + if (pbTest[0] == 0xcc && pbTest[1] == 0xcc) { + break; + } + } + +#if 0 + // Then we check all of the code we can find in user32.dll + // + HINSTANCE hInst = LoadLibraryA("user32.dll"); + printf("Loaded: user32.dll: %p\n", hInst); + + s_pbBegin = (PBYTE)hInst; + s_pbLimit = s_pbBegin + DetourGetModuleSize(hInst); + + PBYTE pbEntry = DetourGetEntryPoint(hInst); + (VOID) new BasicBlockLink(pbEntry, "user32.dll"); + + DetourEnumerateExports(hInst, NULL, ExportCallback); + + ULONG nIns = 0; + for (BasicBlockLink *pLink = BasicBlockLink::GetListHead(); + pLink; pLink = pLink->Next()) { + + nIns += TestDetourCopyInstruction(pLink->m_pbEntry, pLink->m_pszName); + if (nIns > 100000) { + break; + } + } + printf("Disassembled %d instructions.\n", nIns); +#endif +#endif // DETOURS_X86 || DETOURS_X64 + +#ifdef DETOURS_ARM + // Create an output buffer and fill it with debugbreaks. + // + PBYTE pbBuffer + = (PBYTE)VirtualAlloc(NULL, 0x400, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE); + for (PBYTE pbOut = pbBuffer; pbOut < pbBuffer + 0x400;) { + *pbOut++ = 0xfe; + *pbOut++ = 0xde; + } + PBYTE pbDst = pbBuffer; + PVOID pvDstPool = (PVOID)(pbBuffer + 0x400); + + // First we check the pre-canned TestCodes from disasm.asm + // + PBYTE pbBegin = (PBYTE)DetourCodeFromPointer(TestCodes, NULL); + printf("%p: (TestCodes %p) => %p\n", pbBegin, TestCodes, pbBuffer); + for (PBYTE pbSrc = pbBegin;;) { + if (pbSrc[0] != 0xfe && pbSrc[1] != 0xde) { // BREAK + printf("%08x ", pbSrc - pbBegin); + DumpMemoryFragment(pbSrc, 8, 8); + printf("\n"); + printf("failed on last.\n"); + return 1; + } + pbSrc += 2; + *pbDst++ = 0xfe; + *pbDst++ = 0xde; + + if ((pbSrc[0] == 0x00 && pbSrc[1] == 0xbf) && // NOP + (pbSrc[2] != 0xfe && pbSrc[3] != 0xde)) { // BREAK + // Skip over a single NOP so we can test alignment. + pbSrc += 2; + } + + if ((pbSrc[0] == 0x00 && pbSrc[1] == 0xbf) && // NOP + (pbSrc[2] != 0xfe && pbSrc[3] != 0xde)) { // BREAK + // If there is a second NOP, then we insert alignment. + pbSrc += 2; + *pbDst++ = 0x00; + *pbDst++ = 0xbf; + } + + + LONG lExtra = 0; + PVOID pbTarget = NULL; + PBYTE pbNext = (PBYTE)DetourCopyInstruction(pbDst, &pvDstPool, pbSrc, &pbTarget, &lExtra); + + LONG cbTest = (LONG)(pbNext - pbSrc); + + printf("%08x ", pbSrc - pbBegin); + DumpMemoryFragment(pbSrc, cbTest, 4); + printf("[%8p] ", pbTarget); + DumpMemoryFragment(pbDst, cbTest + lExtra, 16); + printf("\n"); + + if (pbSrc[cbTest] != 0xfe || pbSrc[cbTest+1] != 0xde) { + printf("%p: failed! (pbSrc[n]=%02x, pbSrc[n+1]=%02x\n", + pbSrc, + pbSrc[cbTest], pbSrc[cbTest+1]); + __debugbreak(); + pbNext = (PBYTE)DetourCopyInstruction(pbDst, &pvDstPool, pbSrc, &pbTarget, &lExtra); + cbTest = (LONG)(pbNext - pbSrc); + return 1; + } + + pbDst += cbTest + lExtra; + pbSrc += cbTest; + + if (pbSrc[0] == 0xfe && pbSrc[1] == 0xde && + pbSrc[2] == 0xfe && pbSrc[3] == 0xde) { + break; + } + } + +#if 0 + // Then we check all of the code we can find in user32.dll + // + HINSTANCE hInst = LoadLibraryA("user32.dll"); + printf("Loaded: user32.dll: %p\n", hInst); + + s_pbBegin = (PBYTE)hInst; + s_pbLimit = s_pbBegin + DetourGetModuleSize(hInst); + + PBYTE pbEntry = DetourGetEntryPoint(hInst); + (VOID) new BasicBlockLink(pbEntry, "user32.dll"); + + DetourEnumerateExports(hInst, NULL, ExportCallback); + + ULONG nIns = 0; + for (BasicBlockLink *pLink = BasicBlockLink::GetListHead(); + pLink; pLink = pLink->Next()) { + + nIns += TestDetourCopyInstruction(pLink->m_pbEntry, pLink->m_pszName); + if (nIns > 100000) { + break; + } + } + printf("Disassembled %d instructions.\n", nIns); +#endif +#endif // DETOURS_ARM + + return 0; +} +// +///////////////////////////////////////////////////////////////// End of File. |