703 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			703 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
| /////////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| //  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.
 |