// Copyright (c) Microsoft Corporation. All rights reserved. #include "detours_disasm.h" #include #define c_LR 30 // The register number for the Link Register #define c_SP 31 // The register number for the Stack Pointer #define c_NOP 0xd503201f // A nop instruction #define c_BREAK (0xd4200000 | (0xf000 << 5)) // A break instruction // // Problematic instructions: // // ADR 0ll10000 hhhhhhhh hhhhhhhh hhhddddd & 0x9f000000 == 0x10000000 (l = low, h = high, d = Rd) // ADRP 1ll10000 hhhhhhhh hhhhhhhh hhhddddd & 0x9f000000 == 0x90000000 (l = low, h = high, d = Rd) // // B.cond 01010100 iiiiiiii iiiiiiii iii0cccc & 0xff000010 == 0x54000000 (i = delta = SignExtend(imm19:00, 64), c = cond) // // B 000101ii iiiiiiii iiiiiiii iiiiiiii & 0xfc000000 == 0x14000000 (i = delta = SignExtend(imm26:00, 64)) // BL 100101ii iiiiiiii iiiiiiii iiiiiiii & 0xfc000000 == 0x94000000 (i = delta = SignExtend(imm26:00, 64)) // // CBNZ z0110101 iiiiiiii iiiiiiii iiittttt & 0x7f000000 == 0x35000000 (z = size, i = delta = SignExtend(imm19:00, 64), t = Rt) // CBZ z0110100 iiiiiiii iiiiiiii iiittttt & 0x7f000000 == 0x34000000 (z = size, i = delta = SignExtend(imm19:00, 64), t = Rt) // // LDR Wt 00011000 iiiiiiii iiiiiiii iiittttt & 0xff000000 == 0x18000000 (i = SignExtend(imm19:00, 64), t = Rt) // LDR Xt 01011000 iiiiiiii iiiiiiii iiittttt & 0xff000000 == 0x58000000 (i = SignExtend(imm19:00, 64), t = Rt) // LDRSW 10011000 iiiiiiii iiiiiiii iiittttt & 0xff000000 == 0x98000000 (i = SignExtend(imm19:00, 64), t = Rt) // PRFM 11011000 iiiiiiii iiiiiiii iiittttt & 0xff000000 == 0xd8000000 (i = SignExtend(imm19:00, 64), t = Rt) // LDR St 00011100 iiiiiiii iiiiiiii iiittttt & 0xff000000 == 0x1c000000 (i = SignExtend(imm19:00, 64), t = Rt) // LDR Dt 01011100 iiiiiiii iiiiiiii iiittttt & 0xff000000 == 0x5c000000 (i = SignExtend(imm19:00, 64), t = Rt) // LDR Qt 10011100 iiiiiiii iiiiiiii iiittttt & 0xff000000 == 0x9c000000 (i = SignExtend(imm19:00, 64), t = Rt) // LDR inv 11011100 iiiiiiii iiiiiiii iiittttt & 0xff000000 == 0xdc000000 (i = SignExtend(imm19:00, 64), t = Rt) // // TBNZ z0110111 bbbbbiii iiiiiiii iiittttt & 0x7f000000 == 0x37000000 (z = size, b = bitnum, i = SignExtend(imm14:00, 64), t = Rt) // TBZ z0110110 bbbbbiii iiiiiiii iiittttt & 0x7f000000 == 0x36000000 (z = size, b = bitnum, i = SignExtend(imm14:00, 64), t = Rt) // class CDetourDis { public: explicit CDetourDis() = default; uint8_t* CopyInstruction(uint8_t* pDst, uint8_t* pSrc, uint8_t* *ppTarget, int32_t *plExtra); public: typedef uint8_t (CDetourDis::* COPYFUNC)(uint8_t* pbDst, uint8_t* pbSrc); union AddImm12 { uint32_t Assembled; struct { uint32_t Rd : 5; // Destination register uint32_t Rn : 5; // Source register uint32_t Imm12 : 12; // 12-bit immediate uint32_t Shift : 2; // shift (must be 0 or 1) uint32_t Opcode1 : 7; // Must be 0010001 == 0x11 uint32_t Size : 1; // 0 = 32-bit, 1 = 64-bit } s; static uint32_t Assemble(uint32_t size, uint32_t rd, uint32_t rn, uint32_t imm, uint32_t shift) { AddImm12 temp; temp.s.Rd = rd; temp.s.Rn = rn; temp.s.Imm12 = imm & 0xfff; temp.s.Shift = shift; temp.s.Opcode1 = 0x11; temp.s.Size = size; return temp.Assembled; } static uint32_t AssembleAdd32(uint32_t rd, uint32_t rn, uint32_t imm, uint32_t shift) { return Assemble(0, rd, rn, imm, shift); } static uint32_t AssembleAdd64(uint32_t rd, uint32_t rn, uint32_t imm, uint32_t shift) { return Assemble(1, rd, rn, imm, shift); } }; union Adr19 { uint32_t Assembled; struct { uint32_t Rd : 5; // Destination register uint32_t Imm19 : 19; // 19-bit upper immediate uint32_t Opcode1 : 5; // Must be 10000 == 0x10 uint32_t Imm2 : 2; // 2-bit lower immediate uint32_t Type : 1; // 0 = ADR, 1 = ADRP } s; inline int32_t Imm() const { uint32_t Imm = (s.Imm19 << 2) | s.Imm2; return (int32_t)(Imm << 11) >> 11; } static uint32_t Assemble(uint32_t type, uint32_t rd, int32_t delta) { Adr19 temp; temp.s.Rd = rd; temp.s.Imm19 = (delta >> 2) & 0x7ffff; temp.s.Opcode1 = 0x10; temp.s.Imm2 = delta & 3; temp.s.Type = type; return temp.Assembled; } static uint32_t AssembleAdr(uint32_t rd, int32_t delta) { return Assemble(0, rd, delta); } static uint32_t AssembleAdrp(uint32_t rd, int32_t delta) { return Assemble(1, rd, delta); } }; union Bcc19 { uint32_t Assembled; struct { uint32_t Condition : 4; // Condition uint32_t Opcode1 : 1; // Must be 0 uint32_t Imm19 : 19; // 19-bit immediate uint32_t Opcode2 : 8; // Must be 01010100 == 0x54 } s; inline int32_t Imm() const { return (int32_t)(s.Imm19 << 13) >> 11; } static uint32_t AssembleBcc(uint32_t condition, int32_t delta) { Bcc19 temp; temp.s.Condition = condition; temp.s.Opcode1 = 0; temp.s.Imm19 = delta >> 2; temp.s.Opcode2 = 0x54; return temp.Assembled; } }; union Branch26 { uint32_t Assembled; struct { uint32_t Imm26 : 26; // 26-bit immediate uint32_t Opcode1 : 5; // Must be 00101 == 0x5 uint32_t Link : 1; // 0 = B, 1 = BL } s; inline int32_t Imm() const { return (int32_t)(s.Imm26 << 6) >> 4; } static uint32_t Assemble(uint32_t link, int32_t delta) { Branch26 temp; temp.s.Imm26 = delta >> 2; temp.s.Opcode1 = 0x5; temp.s.Link = link; return temp.Assembled; } static uint32_t AssembleB(int32_t delta) { return Assemble(0, delta); } static uint32_t AssembleBl(int32_t delta) { return Assemble(1, delta); } }; union Br { uint32_t Assembled; struct { uint32_t Opcode1 : 5; // Must be 00000 == 0 uint32_t Rn : 5; // Register number uint32_t Opcode2 : 22; // Must be 1101011000011111000000 == 0x3587c0 for Br // 0x358fc0 for Brl } s; static uint32_t Assemble(uint32_t rn, bool link) { Br temp; temp.s.Opcode1 = 0; temp.s.Rn = rn; temp.s.Opcode2 = 0x3587c0; if (link) temp.Assembled |= 0x00200000; return temp.Assembled; } static uint32_t AssembleBr(uint32_t rn) { return Assemble(rn, false); } static uint32_t AssembleBrl(uint32_t rn) { return Assemble(rn, true); } }; union Cbz19 { uint32_t Assembled; struct { uint32_t Rt : 5; // Register to test uint32_t Imm19 : 19; // 19-bit immediate uint32_t Nz : 1; // 0 = CBZ, 1 = CBNZ uint32_t Opcode1 : 6; // Must be 011010 == 0x1a uint32_t Size : 1; // 0 = 32-bit, 1 = 64-bit } s; inline int32_t Imm() const { return (int32_t)(s.Imm19 << 13) >> 11; } static uint32_t Assemble(uint32_t size, uint32_t nz, uint32_t rt, int32_t delta) { Cbz19 temp; temp.s.Rt = rt; temp.s.Imm19 = delta >> 2; temp.s.Nz = nz; temp.s.Opcode1 = 0x1a; temp.s.Size = size; return temp.Assembled; } }; union LdrLit19 { uint32_t Assembled; struct { uint32_t Rt : 5; // Destination register uint32_t Imm19 : 19; // 19-bit immediate uint32_t Opcode1 : 2; // Must be 0 uint32_t FpNeon : 1; // 0 = LDR Wt/LDR Xt/LDRSW/PRFM, 1 = LDR St/LDR Dt/LDR Qt uint32_t Opcode2 : 3; // Must be 011 = 3 uint32_t Size : 2; // 00 = LDR Wt/LDR St, 01 = LDR Xt/LDR Dt, 10 = LDRSW/LDR Qt, 11 = PRFM/invalid } s; inline int32_t Imm() const { return (int32_t)(s.Imm19 << 13) >> 11; } static uint32_t Assemble(uint32_t size, uint32_t fpneon, uint32_t rt, int32_t delta) { LdrLit19 temp; temp.s.Rt = rt; temp.s.Imm19 = delta >> 2; temp.s.Opcode1 = 0; temp.s.FpNeon = fpneon; temp.s.Opcode2 = 3; temp.s.Size = size; return temp.Assembled; } }; union LdrFpNeonImm9 { uint32_t Assembled; struct { uint32_t Rt : 5; // Destination register uint32_t Rn : 5; // Base register uint32_t Imm12 : 12; // 12-bit immediate uint32_t Opcode1 : 1; // Must be 1 == 1 uint32_t Opc : 1; // Part of size uint32_t Opcode2 : 6; // Must be 111101 == 0x3d uint32_t Size : 2; // Size (0=8-bit, 1=16-bit, 2=32-bit, 3=64-bit, 4=128-bit) } s; static uint32_t Assemble(uint32_t size, uint32_t rt, uint32_t rn, uint32_t imm) { LdrFpNeonImm9 temp; temp.s.Rt = rt; temp.s.Rn = rn; temp.s.Imm12 = imm; temp.s.Opcode1 = 1; temp.s.Opc = size >> 2; temp.s.Opcode2 = 0x3d; temp.s.Size = size & 3; return temp.Assembled; } }; union Mov16 { uint32_t Assembled; struct { uint32_t Rd : 5; // Destination register uint32_t Imm16 : 16; // Immediate uint32_t Shift : 2; // Shift amount (0=0, 1=16, 2=32, 3=48) uint32_t Opcode : 6; // Must be 100101 == 0x25 uint32_t Type : 2; // 0 = MOVN, 1 = reserved, 2 = MOVZ, 3 = MOVK uint32_t Size : 1; // 0 = 32-bit, 1 = 64-bit } s; static uint32_t Assemble(uint32_t size, uint32_t type, uint32_t rd, uint32_t imm, uint32_t shift) { Mov16 temp; temp.s.Rd = rd; temp.s.Imm16 = imm; temp.s.Shift = shift; temp.s.Opcode = 0x25; temp.s.Type = type; temp.s.Size = size; return temp.Assembled; } static uint32_t AssembleMovn32(uint32_t rd, uint32_t imm, uint32_t shift) { return Assemble(0, 0, rd, imm, shift); } static uint32_t AssembleMovn64(uint32_t rd, uint32_t imm, uint32_t shift) { return Assemble(1, 0, rd, imm, shift); } static uint32_t AssembleMovz32(uint32_t rd, uint32_t imm, uint32_t shift) { return Assemble(0, 2, rd, imm, shift); } static uint32_t AssembleMovz64(uint32_t rd, uint32_t imm, uint32_t shift) { return Assemble(1, 2, rd, imm, shift); } static uint32_t AssembleMovk32(uint32_t rd, uint32_t imm, uint32_t shift) { return Assemble(0, 3, rd, imm, shift); } static uint32_t AssembleMovk64(uint32_t rd, uint32_t imm, uint32_t shift) { return Assemble(1, 3, rd, imm, shift); } }; union Tbz14 { uint32_t Assembled; struct { uint32_t Rt : 5; // Register to test uint32_t Imm14 : 14; // 14-bit immediate uint32_t Bit : 5; // 5-bit index uint32_t Nz : 1; // 0 = TBZ, 1 = TBNZ uint32_t Opcode1 : 6; // Must be 011011 == 0x1b uint32_t Size : 1; // 0 = 32-bit, 1 = 64-bit } s; inline int32_t Imm() const { return (int32_t)(s.Imm14 << 18) >> 16; } static uint32_t Assemble(uint32_t size, uint32_t nz, uint32_t rt, uint32_t bit, int32_t delta) { Tbz14 temp; temp.s.Rt = rt; temp.s.Imm14 = delta >> 2; temp.s.Bit = bit; temp.s.Nz = nz; temp.s.Opcode1 = 0x1b; temp.s.Size = size; return temp.Assembled; } }; protected: uint8_t PureCopy32(uint8_t* pSource, uint8_t* pDest); uint8_t EmitMovImmediate(uint32_t*& pDstInst, uint8_t rd, uint64_t immediate); uint8_t CopyAdr(uint8_t* pSource, uint8_t* pDest, uint32_t instruction); uint8_t CopyBcc(uint8_t* pSource, uint8_t* pDest, uint32_t instruction); uint8_t CopyB(uint8_t* pSource, uint8_t* pDest, uint32_t instruction); uint8_t CopyBl(uint8_t* pSource, uint8_t* pDest, uint32_t instruction); uint8_t CopyB_or_Bl(uint8_t* pSource, uint8_t* pDest, uint32_t instruction, bool link); uint8_t CopyCbz(uint8_t* pSource, uint8_t* pDest, uint32_t instruction); uint8_t CopyTbz(uint8_t* pSource, uint8_t* pDest, uint32_t instruction); uint8_t CopyLdrLiteral(uint8_t* pSource, uint8_t* pDest, uint32_t instruction); protected: uint32_t GetInstruction(uint8_t* pSource) { return ((uint32_t*)pSource)[0]; } uint8_t EmitInstruction(uint32_t*& pDstInst, uint32_t instruction) { *pDstInst++ = instruction; return sizeof(uint32_t); } protected: uint8_t* m_pbTarget = nullptr; uint8_t m_rbScratchDst[128] {}; // matches or exceeds rbCode }; uint8_t CDetourDis::PureCopy32(uint8_t* pSource, uint8_t* pDest) { *(uint32_t *)pDest = *(uint32_t*)pSource; return sizeof(uint32_t); } /////////////////////////////////////////////////////////// Disassembler Code. // uint8_t* CDetourDis::CopyInstruction(uint8_t* pDst, uint8_t* pSrc, uint8_t* *ppTarget, int32_t *plExtra) { if (pDst == nullptr) { pDst = m_rbScratchDst; } uint32_t Instruction = GetInstruction(pSrc); uint32_t CopiedSize; if ((Instruction & 0x1f000000) == 0x10000000) { CopiedSize = CopyAdr(pSrc, pDst, Instruction); } else if ((Instruction & 0xff000010) == 0x54000000) { CopiedSize = CopyBcc(pSrc, pDst, Instruction); } else if ((Instruction & 0x7c000000) == 0x14000000) { CopiedSize = CopyB_or_Bl(pSrc, pDst, Instruction, (Instruction & 0x80000000) != 0); } else if ((Instruction & 0x7e000000) == 0x34000000) { CopiedSize = CopyCbz(pSrc, pDst, Instruction); } else if ((Instruction & 0x7e000000) == 0x36000000) { CopiedSize = CopyTbz(pSrc, pDst, Instruction); } else if ((Instruction & 0x3b000000) == 0x18000000) { CopiedSize = CopyLdrLiteral(pSrc, pDst, Instruction); } else { CopiedSize = PureCopy32(pSrc, pDst); } // If the target is needed, store our target if (ppTarget) { *ppTarget = m_pbTarget; } if (plExtra) { *plExtra = CopiedSize - sizeof(uint32_t); } return pSrc + 4; } uint8_t CDetourDis::EmitMovImmediate(uint32_t*& pDstInst, uint8_t rd, uint64_t immediate) { uint32_t piece[4]; piece[3] = (uint32_t)((immediate >> 48) & 0xffff); piece[2] = (uint32_t)((immediate >> 32) & 0xffff); piece[1] = (uint32_t)((immediate >> 16) & 0xffff); piece[0] = (uint32_t)((immediate >> 0) & 0xffff); int count = 0; // special case: MOVN with 32-bit dest if (piece[3] == 0 && piece[2] == 0 && piece[1] == 0xffff) { EmitInstruction(pDstInst, Mov16::AssembleMovn32(rd, piece[0] ^ 0xffff, 0)); count++; } // MOVN/MOVZ with 64-bit dest else { int zero_pieces = (piece[3] == 0x0000) + (piece[2] == 0x0000) + (piece[1] == 0x0000) + (piece[0] == 0x0000); int ffff_pieces = (piece[3] == 0xffff) + (piece[2] == 0xffff) + (piece[1] == 0xffff) + (piece[0] == 0xffff); uint32_t defaultPiece = (ffff_pieces > zero_pieces) ? 0xffff : 0x0000; bool first = true; for (int pieceNum = 3; pieceNum >= 0; pieceNum--) { uint32_t curPiece = piece[pieceNum]; if (curPiece != defaultPiece || (pieceNum == 0 && first)) { count++; if (first) { if (defaultPiece == 0xffff) { EmitInstruction(pDstInst, Mov16::AssembleMovn64(rd, curPiece ^ 0xffff, pieceNum)); } else { EmitInstruction(pDstInst, Mov16::AssembleMovz64(rd, curPiece, pieceNum)); } first = false; } else { EmitInstruction(pDstInst, Mov16::AssembleMovk64(rd, curPiece, pieceNum)); } } } } return (uint8_t)(count * sizeof(uint32_t)); } uint8_t CDetourDis::CopyAdr(uint8_t* pSource, uint8_t* pDest, uint32_t instruction) { Adr19& decoded = (Adr19&)(instruction); uint32_t* pDstInst = (uint32_t*)(pDest); // ADR case if (decoded.s.Type == 0) { uint8_t* pTarget = pSource + decoded.Imm(); int64_t delta = pTarget - pDest; int64_t deltaPage = ((std::ptrdiff_t)pTarget >> 12) - ((std::ptrdiff_t)pDest >> 12); // output as ADR if (delta >= -(1 << 20) && delta < (1 << 20)) { EmitInstruction(pDstInst, Adr19::AssembleAdr(decoded.s.Rd, (int32_t)delta)); } // output as ADRP; ADD else if (deltaPage >= -(1 << 20) && (deltaPage < (1 << 20))) { EmitInstruction(pDstInst, Adr19::AssembleAdrp(decoded.s.Rd, (int32_t)deltaPage)); EmitInstruction(pDstInst, AddImm12::AssembleAdd32(decoded.s.Rd, decoded.s.Rd, ((std::ptrdiff_t)pTarget) & 0xfff, 0)); } // output as immediate move else { EmitMovImmediate(pDstInst, decoded.s.Rd, (std::ptrdiff_t)pTarget); } } // ADRP case else { uint8_t* pTarget = (uint8_t*)((((std::ptrdiff_t)pSource >> 12) + decoded.Imm()) << 12); int64_t deltaPage = ((std::ptrdiff_t)pTarget >> 12) - ((std::ptrdiff_t)pDest >> 12); // output as ADRP if (deltaPage >= -(1 << 20) && (deltaPage < (1 << 20))) { EmitInstruction(pDstInst, Adr19::AssembleAdrp(decoded.s.Rd, (int32_t)deltaPage)); } // output as immediate move else { EmitMovImmediate(pDstInst, decoded.s.Rd, (std::ptrdiff_t)pTarget); } } return (uint8_t)((uint8_t*)pDstInst - pDest); } uint8_t CDetourDis::CopyBcc(uint8_t* pSource, uint8_t* pDest, uint32_t instruction) { Bcc19& decoded = (Bcc19&)(instruction); uint32_t* pDstInst = (uint32_t*)(pDest); uint8_t* pTarget = pSource + decoded.Imm(); m_pbTarget = pTarget; int64_t delta = pTarget - pDest; int64_t delta4 = pTarget - (pDest + 4); // output as BCC if (delta >= -(1 << 20) && delta < (1 << 20)) { EmitInstruction(pDstInst, Bcc19::AssembleBcc(decoded.s.Condition, (int32_t)delta)); } // output as BCC ; B else if (delta4 >= -(1 << 27) && (delta4 < (1 << 27))) { EmitInstruction(pDstInst, Bcc19::AssembleBcc(decoded.s.Condition ^ 1, 8)); EmitInstruction(pDstInst, Branch26::AssembleB((int32_t)delta4)); } // output as MOV x17, Target; BCC ; BR x17 (BIG assumption that x17 isn't being used for anything!!) else { EmitMovImmediate(pDstInst, 17, (std::ptrdiff_t)pTarget); EmitInstruction(pDstInst, Bcc19::AssembleBcc(decoded.s.Condition ^ 1, 8)); EmitInstruction(pDstInst, Br::AssembleBr(17)); } return (uint8_t)((uint8_t*)pDstInst - pDest); } uint8_t CDetourDis::CopyB_or_Bl(uint8_t* pSource, uint8_t* pDest, uint32_t instruction, bool link) { Branch26& decoded = (Branch26&)(instruction); uint32_t* pDstInst = (uint32_t*)(pDest); uint8_t* pTarget = pSource + decoded.Imm(); m_pbTarget = pTarget; int64_t delta = pTarget - pDest; // output as B or BRL if (delta >= -(1 << 27) && (delta < (1 << 27))) { EmitInstruction(pDstInst, Branch26::Assemble(link, (int32_t)delta)); } // output as MOV x17, Target; BR or BRL x17 (BIG assumption that x17 isn't being used for anything!!) else { EmitMovImmediate(pDstInst, 17, (std::ptrdiff_t)pTarget); EmitInstruction(pDstInst, Br::Assemble(17, link)); } return (uint8_t)((uint8_t*)pDstInst - pDest); } uint8_t CDetourDis::CopyB(uint8_t* pSource, uint8_t* pDest, uint32_t instruction) { return CopyB_or_Bl(pSource, pDest, instruction, false); } uint8_t CDetourDis::CopyBl(uint8_t* pSource, uint8_t* pDest, uint32_t instruction) { return CopyB_or_Bl(pSource, pDest, instruction, true); } uint8_t CDetourDis::CopyCbz(uint8_t* pSource, uint8_t* pDest, uint32_t instruction) { Cbz19& decoded = (Cbz19&)(instruction); uint32_t* pDstInst = (uint32_t*)(pDest); uint8_t* pTarget = pSource + decoded.Imm(); m_pbTarget = pTarget; int64_t delta = pTarget - pDest; int64_t delta4 = pTarget - (pDest + 4); // output as CBZ/NZ if (delta >= -(1 << 20) && delta < (1 << 20)) { EmitInstruction(pDstInst, Cbz19::Assemble(decoded.s.Size, decoded.s.Nz, decoded.s.Rt, (int32_t)delta)); } // output as CBNZ/Z ; B else if (delta4 >= -(1 << 27) && (delta4 < (1 << 27))) { EmitInstruction(pDstInst, Cbz19::Assemble(decoded.s.Size, decoded.s.Nz ^ 1, decoded.s.Rt, 8)); EmitInstruction(pDstInst, Branch26::AssembleB((int32_t)delta4)); } // output as MOV x17, Target; CBNZ/Z ; BR x17 (BIG assumption that x17 isn't being used for anything!!) else { EmitMovImmediate(pDstInst, 17, (std::ptrdiff_t)pTarget); EmitInstruction(pDstInst, Cbz19::Assemble(decoded.s.Size, decoded.s.Nz ^ 1, decoded.s.Rt, 8)); EmitInstruction(pDstInst, Br::AssembleBr(17)); } return (uint8_t)((uint8_t*)pDstInst - pDest); } uint8_t CDetourDis::CopyTbz(uint8_t* pSource, uint8_t* pDest, uint32_t instruction) { Tbz14& decoded = (Tbz14&)(instruction); uint32_t* pDstInst = (uint32_t*)(pDest); uint8_t* pTarget = pSource + decoded.Imm(); m_pbTarget = pTarget; int64_t delta = pTarget - pDest; int64_t delta4 = pTarget - (pDest + 4); // output as TBZ/NZ if (delta >= -(1 << 13) && delta < (1 << 13)) { EmitInstruction(pDstInst, Tbz14::Assemble(decoded.s.Size, decoded.s.Nz, decoded.s.Rt, decoded.s.Bit, (int32_t)delta)); } // output as TBNZ/Z ; B else if (delta4 >= -(1 << 27) && (delta4 < (1 << 27))) { EmitInstruction(pDstInst, Tbz14::Assemble(decoded.s.Size, decoded.s.Nz ^ 1, decoded.s.Rt, decoded.s.Bit, 8)); EmitInstruction(pDstInst, Branch26::AssembleB((int32_t)delta4)); } // output as MOV x17, Target; TBNZ/Z ; BR x17 (BIG assumption that x17 isn't being used for anything!!) else { EmitMovImmediate(pDstInst, 17, (std::ptrdiff_t)pTarget); EmitInstruction(pDstInst, Tbz14::Assemble(decoded.s.Size, decoded.s.Nz ^ 1, decoded.s.Rt, decoded.s.Bit, 8)); EmitInstruction(pDstInst, Br::AssembleBr(17)); } return (uint8_t)((uint8_t*)pDstInst - pDest); } uint8_t CDetourDis::CopyLdrLiteral(uint8_t* pSource, uint8_t* pDest, uint32_t instruction) { LdrLit19& decoded = (LdrLit19&)(instruction); uint32_t* pDstInst = (uint32_t*)(pDest); uint8_t* pTarget = pSource + decoded.Imm(); int64_t delta = pTarget - pDest; // output as LDR if (delta >= -(1 << 21) && delta < (1 << 21)) { EmitInstruction(pDstInst, LdrLit19::Assemble(decoded.s.Size, decoded.s.FpNeon, decoded.s.Rt, (int32_t)delta)); } // output as move immediate else if (decoded.s.FpNeon == 0) { uint64_t value = 0; switch (decoded.s.Size) { case 0: value = *(uint32_t*)pTarget; break; case 1: value = *(uint64_t*)pTarget; break; case 2: value = *(int32_t*)pTarget; break; } EmitMovImmediate(pDstInst, decoded.s.Rt, value); } // FP/NEON register: compute address in x17 and load from there (BIG assumption that x17 isn't being used for anything!!) else { EmitMovImmediate(pDstInst, 17, (std::ptrdiff_t)pTarget); EmitInstruction(pDstInst, LdrFpNeonImm9::Assemble(2 + decoded.s.Size, decoded.s.Rt, 17, 0)); } return (uint8_t)((uint8_t*)pDstInst - pDest); } void* internal_detour_copy_instruction(void* dst, void* src, void** out_target, int32_t* out_extra_len) { CDetourDis state; return (void*)state.CopyInstruction((uint8_t*)dst, (uint8_t*)src, (uint8_t**)out_target, out_extra_len); }