void CDisAsmVu::DrawInstructionDetails(Framework::Win32::CDeviceContext& deviceContext, uint32 address, int y) { assert((address & 0x07) == 0); uint32 lowerInstruction = GetInstruction(address + 0); uint32 upperInstruction = GetInstruction(address + 4); std::tstring instructionCode = lexical_cast_hex<std::tstring>(upperInstruction, 8) + _T(" ") + lexical_cast_hex<std::tstring>(lowerInstruction, 8); deviceContext.TextOut(100, y, instructionCode.c_str()); { char disAsm[256]; m_ctx->m_pArch->GetInstructionMnemonic(m_ctx, address + 4, upperInstruction, disAsm, 256); deviceContext.TextOut(250, y, string_cast<std::tstring>(disAsm).c_str()); } { char disAsm[256]; m_ctx->m_pArch->GetInstructionOperands(m_ctx, address + 4, upperInstruction, disAsm, 256); deviceContext.TextOut(350, y, string_cast<std::tstring>(disAsm).c_str()); } { char disAsm[256]; m_ctx->m_pArch->GetInstructionMnemonic(m_ctx, address + 0, lowerInstruction, disAsm, 256); deviceContext.TextOut(600, y, string_cast<std::tstring>(disAsm).c_str()); } { char disAsm[256]; m_ctx->m_pArch->GetInstructionOperands(m_ctx, address + 0, lowerInstruction, disAsm, 256); deviceContext.TextOut(700, y, string_cast<std::tstring>(disAsm).c_str()); } }
bool VIRTUALMACHINE::step(bool skip) { bool result= false; VMREGTYPE ip= 0; OPCODE opcode; if(GetRegister(IP,ip) && GetInstruction((VPVOID)ip,opcode) && opcode) { INSTRUCTIONMAP::iterator it= instructions.find(opcode); if(it!=instructions.end()) { INSTRUCTION* inst= it->second; int operandlength= inst->GetOperands(opcode,(VPVOID)ip+sizeof(opcode)); if(operandlength>=0) { ip+= sizeof(opcode)+operandlength; if(SetRegister(IP,(VMREGTYPE)ip)) { result= skip || inst->execute(); } } } else { BadOpcodeHandler(opcode,(VPVOID)ip); } } return result; }
/** --------------------------------------------------------------------------- \brief calculate instruction length of Addr \param \return \code \endcode -----------------------------------------------------------------------------*/ int GetInstructionLength(BYTE* Addr) { #ifdef _USE_LIBDASM_LIB INSTRUCTION instr = {0}; int Len = get_instruction(&instr, Addr, MODE_32); // check illegal opcode if (0 == Len) { _ASSERTE(!"get_instruction"); return -1; } #ifdef _DEBUG char string[256] = {0}; get_instruction_string(&instr, FORMAT_INTEL, 0, string, sizeof(string)); _tprintf(TEXT("%s\n"), string); #endif return Len; #else DISASSEMBLER Disassembler; INSTRUCTION * Instruction = NULL; if (TRUE != InitDisassembler(&Disassembler, ARCH_X86)) { _ASSERTE(!"InitDisassembler"); return -1; } ULONG Flags = DISASM_DISASSEMBLE | DISASM_DECODE | DISASM_STOPONERROR | DISASM_STOPONANOMALY | DISASM_STOPONRETURN; Instruction = GetInstruction(&Disassembler, (ULONG)Addr, (PBYTE)Addr, Flags); if (!Instruction) { _ASSERTE(!"GetInstruction"); CloseDisassembler(&Disassembler); return -1; } #ifdef _DEBUG DumpInstruction(Instruction, TRUE, TRUE); #endif int Len = Instruction->Length; CloseDisassembler(&Disassembler); return Len; #endif//_USE_LIBDASM_LIB }
static size_t dpCopyInstructions(void *dst, void *src, size_t minlen) { #ifdef dpWithTDisasm size_t len = 0; #ifdef _M_X64 ARCHITECTURE_TYPE arch = ARCH_X64; #elif defined _M_IX86 ARCHITECTURE_TYPE arch = ARCH_X86; #endif DISASSEMBLER dis; if(InitDisassembler(&dis, arch)) { INSTRUCTION* pins = NULL; U8* pLoc = (U8*)src; U8* pDst = (U8*)dst; DWORD dwFlags = DISASM_SUPPRESSERRORS; while( len<minlen ) { pins = GetInstruction(&dis, (ULONG_PTR)pLoc, pLoc, dwFlags); if(!pins) { break; } if(pins->Type == ITYPE_RET ) { break; } //// todo: call or jmp //if(pins->Type == ITYPE_BRANCH ) break; //if(pins->Type == ITYPE_BRANCHCC) break; //if(pins->Type == ITYPE_CALL ) break; //if(pins->Type == ITYPE_CALLCC ) break; switch(pLoc[0]) { // call & jmp case 0xE8: case 0xE9: { int rva = *(int*)(pLoc+1); pDst[0] = pLoc[0]; *(DWORD*)(pDst+1) = (DWORD)((ptrdiff_t)(pLoc+rva)-(ptrdiff_t)(pDst)); } break; default: memcpy(pDst, pLoc, pins->Length); break; } len += pins->Length; pLoc += pins->Length; pDst += pins->Length; } CloseDisassembler(&dis); } return len; #else // dpWithTDisasm memcpy(dst, src, minlen); return minlen; #endif // dpWithTDisasm }
std::tstring CDisAsmVu::GetInstructionDetailsText(uint32 address) { assert((address & 0x07) == 0); uint32 lowerInstruction = GetInstruction(address + 0); uint32 upperInstruction = GetInstruction(address + 4); std::tstring result; result += lexical_cast_hex<std::tstring>(address, 8) + _T(" "); result += lexical_cast_hex<std::tstring>(upperInstruction, 8) + _T(" ") + lexical_cast_hex<std::tstring>(lowerInstruction, 8) + _T(" "); char disasm[256]; m_ctx->m_pArch->GetInstructionMnemonic(m_ctx, address + 4, upperInstruction, disasm, countof(disasm)); result += string_cast<std::tstring>(disasm); for(size_t j = strlen(disasm); j < 15; j++) { result += _T(" "); } m_ctx->m_pArch->GetInstructionOperands(m_ctx, address + 4, upperInstruction, disasm, countof(disasm)); result += string_cast<std::tstring>(disasm); for(size_t j = strlen(disasm); j < 31; j++) { result += _T(" "); } m_ctx->m_pArch->GetInstructionMnemonic(m_ctx, address + 0, lowerInstruction, disasm, countof(disasm)); result += string_cast<std::tstring>(disasm); for(size_t j = strlen(disasm); j < 16; j++) { result += _T(" "); } m_ctx->m_pArch->GetInstructionOperands(m_ctx, address + 0, lowerInstruction, disasm, countof(disasm)); result += string_cast<std::tstring>(disasm); return result; }
//========================================================================= // Examine the machine code at the target function's entry point, and // skip bytes in a way that we'll always end on an instruction boundary. // We also detect branches and subroutine calls (as well as returns) // at which point disassembly must stop. // Finally, detect and collect information on IP-relative instructions // that we can patch. static DWORD DisassembleAndSkip(PVOID pFunction, DWORD dwMinLen, MHOOKS_PATCHDATA* pdata) { DWORD dwRet = 0; pdata->nLimitDown = 0; pdata->nLimitUp = 0; pdata->nRipCnt = 0; #ifdef _M_IX86 ARCHITECTURE_TYPE arch = ARCH_X86; #elif defined _M_X64 ARCHITECTURE_TYPE arch = ARCH_X64; #else #error unsupported platform #endif DISASSEMBLER dis; if (InitDisassembler(&dis, arch)) { INSTRUCTION* pins = NULL; U8* pLoc = (U8*)pFunction; DWORD dwFlags = DISASM_DECODE | DISASM_DISASSEMBLE | DISASM_ALIGNOUTPUT; ODPRINTF((L"mhooks: DisassembleAndSkip: Disassembling %p", pLoc)); while ( (dwRet < dwMinLen) && (pins = GetInstruction(&dis, (ULONG_PTR)pLoc, pLoc, dwFlags)) ) { ODPRINTF(("mhooks: DisassembleAndSkip: %p:(0x%2.2x) %s", pLoc, pins->Length, pins->String)); if (pins->Type == ITYPE_RET ) break; if (pins->Type == ITYPE_BRANCH ) break; if (pins->Type == ITYPE_BRANCHCC) break; if (pins->Type == ITYPE_CALL ) break; if (pins->Type == ITYPE_CALLCC ) break; #if defined _M_X64 BOOL bProcessRip = FALSE; // mov or lea to register from rip+imm32 if ((pins->Type == ITYPE_MOV || pins->Type == ITYPE_LEA) && (pins->X86.Relative) && (pins->X86.OperandSize == 8) && (pins->OperandCount == 2) && (pins->Operands[1].Flags & OP_IPREL) && (pins->Operands[1].Register == AMD64_REG_RIP)) { // rip-addressing "mov reg, [rip+imm32]" ODPRINTF((L"mhooks: DisassembleAndSkip: found OP_IPREL on operand %d with displacement 0x%x (in memory: 0x%x)", 1, pins->X86.Displacement, *(PDWORD)(pLoc+3))); bProcessRip = TRUE; } // mov or lea to rip+imm32 from register else if ((pins->Type == ITYPE_MOV || pins->Type == ITYPE_LEA) && (pins->X86.Relative) && (pins->X86.OperandSize == 8) && (pins->OperandCount == 2) && (pins->Operands[0].Flags & OP_IPREL) && (pins->Operands[0].Register == AMD64_REG_RIP)) { // rip-addressing "mov [rip+imm32], reg" ODPRINTF((L"mhooks: DisassembleAndSkip: found OP_IPREL on operand %d with displacement 0x%x (in memory: 0x%x)", 0, pins->X86.Displacement, *(PDWORD)(pLoc+3))); bProcessRip = TRUE; } else if ( (pins->OperandCount >= 1) && (pins->Operands[0].Flags & OP_IPREL) ) { // unsupported rip-addressing ODPRINTF((L"mhooks: DisassembleAndSkip: found unsupported OP_IPREL on operand %d", 0)); // dump instruction bytes to the debug output for (DWORD i=0; i<pins->Length; i++) { ODPRINTF((L"mhooks: DisassembleAndSkip: instr byte %2.2d: 0x%2.2x", i, pLoc[i])); } break; } else if ( (pins->OperandCount >= 2) && (pins->Operands[1].Flags & OP_IPREL) ) { // unsupported rip-addressing ODPRINTF((L"mhooks: DisassembleAndSkip: found unsupported OP_IPREL on operand %d", 1)); // dump instruction bytes to the debug output for (DWORD i=0; i<pins->Length; i++) { ODPRINTF((L"mhooks: DisassembleAndSkip: instr byte %2.2d: 0x%2.2x", i, pLoc[i])); } break; } else if ( (pins->OperandCount >= 3) && (pins->Operands[2].Flags & OP_IPREL) ) { // unsupported rip-addressing ODPRINTF((L"mhooks: DisassembleAndSkip: found unsupported OP_IPREL on operand %d", 2)); // dump instruction bytes to the debug output for (DWORD i=0; i<pins->Length; i++) { ODPRINTF((L"mhooks: DisassembleAndSkip: instr byte %2.2d: 0x%2.2x", i, pLoc[i])); } break; } // follow through with RIP-processing if needed if (bProcessRip) { // calculate displacement relative to function start S64 nAdjustedDisplacement = pins->X86.Displacement + (pLoc - (U8*)pFunction); // store displacement values furthest from zero (both positive and negative) if (nAdjustedDisplacement < pdata->nLimitDown) pdata->nLimitDown = nAdjustedDisplacement; if (nAdjustedDisplacement > pdata->nLimitUp) pdata->nLimitUp = nAdjustedDisplacement; // store patch info if (pdata->nRipCnt < MHOOKS_MAX_RIPS) { pdata->rips[pdata->nRipCnt].dwOffset = dwRet + 3; pdata->rips[pdata->nRipCnt].nDisplacement = pins->X86.Displacement; pdata->nRipCnt++; } else { // no room for patch info, stop disassembly break; } } #endif dwRet += pins->Length; pLoc += pins->Length; } CloseDisassembler(&dis); } return dwRet; }
Token GetNextToken() { //When we read the source code line by line, we use two index to indicate the both ends of a source line. //At first, the right end index equals to the left end index: they both are 0. sasm.lexer.iIndex0 = sasm.lexer.iIndex1; if (sasm.lexer.iIndex0 >= strlen(sasm.sourceCode[sasm.lexer.iCurrentSourceLine])) { if (!SkipToNextLine()) return ASM_END_OF_TOKEN_STREAM; } if (sasm.lexer.iState == ASM_LEX_STATE_END_STRING) sasm.lexer.iState = ASM_LEX_STATE_NO_STRING; //locate index to the first non-whitespace character of a source code line if (sasm.lexer.iState != ASM_LEX_STATE_IN_STRING) { while (TRUE) { if (!IsCharWhiteSpace((sasm.sourceCode[sasm.lexer.iCurrentSourceLine][sasm.lexer.iIndex0]))) break; sasm.lexer.iIndex0++; } } sasm.lexer.iIndex1 = sasm.lexer.iIndex0; int isGetEscapeChar = FALSE; //move iIndex1 to the location of next token end while (TRUE) { if (sasm.lexer.iState == ASM_LEX_STATE_IN_STRING) { if (sasm.lexer.iIndex1 >= strlen(sasm.sourceCode[sasm.lexer.iCurrentSourceLine])) { sasm.lexer.currentToken = ASM_TOKEN_TYPE_INVALID; return sasm.lexer.currentToken; } if (sasm.sourceCode[sasm.lexer.iCurrentSourceLine][sasm.lexer.iIndex1] == '\\') { //isGetEscapeChar = TRUE; sasm.lexer.iIndex1 += 2; continue; } if (sasm.sourceCode[sasm.lexer.iCurrentSourceLine][sasm.lexer.iIndex1] == '"') break; sasm.lexer.iIndex1++; } else { if (sasm.lexer.iIndex1 >= strlen(sasm.sourceCode[sasm.lexer.iCurrentSourceLine])) break; if (IsCharDelimiter(sasm.sourceCode[sasm.lexer.iCurrentSourceLine][sasm.lexer.iIndex1])) break; sasm.lexer.iIndex1++; } } if (sasm.lexer.iIndex1 - sasm.lexer.iIndex0 == 0) sasm.lexer.iIndex1++; //Get the next lexeme unsigned int currentTargetIndex = 0; for (int i = sasm.lexer.iIndex0; i < sasm.lexer.iIndex1; i++) { if (sasm.lexer.iState == ASM_LEX_STATE_IN_STRING) if (sasm.sourceCode[sasm.lexer.iCurrentSourceLine][i] == '\\') { switch (sasm.sourceCode[sasm.lexer.iCurrentSourceLine][i + 1]) { case 'a': sasm.lexer.pCurrentLexeme[currentTargetIndex] = '\n'; break; case 'b': sasm.lexer.pCurrentLexeme[currentTargetIndex] = '\b'; break; case 'f': sasm.lexer.pCurrentLexeme[currentTargetIndex] = '\f'; break; case 'n': sasm.lexer.pCurrentLexeme[currentTargetIndex] = '\n'; break; case 'r': sasm.lexer.pCurrentLexeme[currentTargetIndex] = '\r'; break; case 't': sasm.lexer.pCurrentLexeme[currentTargetIndex] = '\t'; break; case 'v': sasm.lexer.pCurrentLexeme[currentTargetIndex] = '\n'; break; case '\\': sasm.lexer.pCurrentLexeme[currentTargetIndex] = '\\'; break; case '\'': sasm.lexer.pCurrentLexeme[currentTargetIndex] = '\''; break; case '"': sasm.lexer.pCurrentLexeme[currentTargetIndex] = '\"'; break; case '0': sasm.lexer.pCurrentLexeme[currentTargetIndex] = '\0'; break; default: break; } currentTargetIndex += 1; i++; continue; } sasm.lexer.pCurrentLexeme[currentTargetIndex] = sasm.sourceCode[sasm.lexer.iCurrentSourceLine][i]; currentTargetIndex++; } sasm.lexer.pCurrentLexeme[currentTargetIndex] = '\0'; /*if (sasm.lexer.iState != ASM_LEX_STATE_IN_STRING) strtoupper(sasm.lexer.pCurrentLexeme);*/ //Decide which token the lexeme is sasm.lexer.currentToken = ASM_TOKEN_TYPE_INVALID; if (strlen(sasm.lexer.pCurrentLexeme) > 1 || sasm.lexer.pCurrentLexeme[0] != '"') { if (sasm.lexer.iState == ASM_LEX_STATE_IN_STRING) { sasm.lexer.currentToken = ASM_TOKEN_TYPE_STRING; return ASM_TOKEN_TYPE_STRING; } } if (IsStringInt(sasm.lexer.pCurrentLexeme)) sasm.lexer.currentToken = ASM_TOKEN_TYPE_INT; if (IsStringFloat(sasm.lexer.pCurrentLexeme)) sasm.lexer.currentToken = ASM_TOKEN_TYPE_FLOAT; if (IsStringIdent(sasm.lexer.pCurrentLexeme)) sasm.lexer.currentToken = ASM_TOKEN_TYPE_IDENT; if (strcmp(sasm.lexer.pCurrentLexeme, ASM_KW_SET_STACK_SIZE) == 0) sasm.lexer.currentToken = ASM_TOKEN_TYPE_SETSTACKSIZE; if (strcmp(sasm.lexer.pCurrentLexeme, ASM_KW_VAR) == 0) sasm.lexer.currentToken = ASM_TOKEN_TYPE_VAR; if (strcmp(sasm.lexer.pCurrentLexeme, ASM_KW_FUNCTION) == 0) sasm.lexer.currentToken = ASM_TOKEN_TYPE_FUNC; if (strcmp(sasm.lexer.pCurrentLexeme, ASM_KW_PARAM) == 0) sasm.lexer.currentToken = ASM_TOKEN_TYPE_PARAM; if (strcmp(sasm.lexer.pCurrentLexeme, ASM_KW_RETVAL) == 0) sasm.lexer.currentToken = ASM_TOKEN_TYPE_REG_RETVAL; if (strlen(sasm.lexer.pCurrentLexeme) == 1) { switch (sasm.lexer.pCurrentLexeme[0]) { case '"': switch (sasm.lexer.iState) { case ASM_LEX_STATE_NO_STRING: sasm.lexer.iState = ASM_LEX_STATE_IN_STRING; break; case ASM_LEX_STATE_IN_STRING: sasm.lexer.iState = ASM_LEX_STATE_END_STRING; } sasm.lexer.currentToken = ASM_TOKEN_TYPE_QUATE; break; case ',': sasm.lexer.currentToken = ASM_TOKEN_TYPE_COMMA; break; case ':': sasm.lexer.currentToken = ASM_TOKEN_TYPE_COLON; break; case '[': sasm.lexer.currentToken = ASM_TOKEN_TYPE_OPEN_BRACKET; break; case ']': sasm.lexer.currentToken = ASM_TOKEN_TYPE_CLOSE_BRACKET; break; case '{': sasm.lexer.currentToken = ASM_TOKEN_TYPE_OPEN_BRACE; break; case '}': sasm.lexer.currentToken = ASM_TOKEN_TYPE_CLOSE_BRACE; break; case '\n': sasm.lexer.currentToken = ASM_TOKEN_TYPE_NEWLINE; break; case '\r': sasm.lexer.currentToken = ASM_TOKEN_TYPE_NEWLINE; break; } } InstrLookup instrLookup; if (GetInstruction(sasm.instrLookup, sasm.lexer.pCurrentLexeme, &instrLookup)) sasm.lexer.currentToken = ASM_TOKEN_TYPE_INSTR; return sasm.lexer.currentToken; }
bool csPixelShaderParser::ParseProgram (iDataBuffer* program) { version = CS_PS_INVALID; csString prog; prog.Append ((char*)program->GetData(), program->GetSize()); // Trim any leading/trailing blank lines prog.Trim (); size_t len = prog.Length (); if (len == 0) { Report (CS_REPORTER_SEVERITY_ERROR, "Empty program!"); return false; } max_registers[CS_PS_REG_TEX] = 4; max_registers[CS_PS_REG_TEMP] = 2; max_registers[CS_PS_REG_CONSTANT] = 8; max_registers[CS_PS_REG_COLOR] = 2; bool hasVersion = false; csStringReader reader (prog); csString line; int lineCount = 0; while (reader.HasMoreLines ()) { if (!reader.GetLine (line)) break; lineCount++; csPSProgramInstruction inst; if(!GetInstruction (line, inst)) return false; // Probably a blank line or comment ... ignore if(inst.instruction == CS_PS_INS_INVALID) continue; // Identify the version bool isVerInstr = (inst.instruction >= CS_PS_INS_PS_1_1) && (inst.instruction <= CS_PS_INS_PS_1_4); if (!hasVersion) { if (!isVerInstr) { Report (CS_REPORTER_SEVERITY_WARNING, "Expected version, got %s", GetInstructionName (inst.instruction)); return false; } switch (inst.instruction) { case CS_PS_INS_PS_1_1: version = CS_PS_1_1; hasVersion = true; break; case CS_PS_INS_PS_1_2: version = CS_PS_1_2; hasVersion = true; break; case CS_PS_INS_PS_1_3: version = CS_PS_1_3; hasVersion = true; break; case CS_PS_INS_PS_1_4: version = CS_PS_1_4; hasVersion = true; max_registers[CS_PS_REG_TEX] = 6; max_registers[CS_PS_REG_TEMP] = 6; break; default: break; } } else if (isVerInstr) { Report (CS_REPORTER_SEVERITY_WARNING, "Invalid version instruction %s in line %d", GetInstructionName (inst.instruction), lineCount); return false; } if(!(version & PS_Instructions[inst.instruction].versions)) { Report (CS_REPORTER_SEVERITY_ERROR, "Pixel Shader version %s does not support instruction %s", GetVersionString (version), CS::Quote::Single (GetInstructionName (inst.instruction))); return false; } if (!isVerInstr) program_instructions.Push (inst); } return true; }