public static IEnumerable <DisassemblyInstruction> Disassemble(IntPtr pAddr, int maxInstructionCount = 0) { if (pAddr == IntPtr.Zero) { throw new ArgumentNullException("pAddr"); } const int maxInstructionSize = 15; const int maxBufferSize = 4096; // default buffer of 100 x maxInstructionSize bytes (1500 bytes) // unless maxInstructionCount is specified var bufferSize = (maxInstructionCount == 0 ? 100 : maxInstructionCount) * maxInstructionSize; // ensure we don't allocate too large a buffer if a huge instruction count is specified bufferSize = Math.Min(bufferSize, maxBufferSize); // allocate an unmanaged buffer (instead of reading into managed byte array) var pBuffer = IntPtr.Zero; try { pBuffer = Process.GetCurrentProcess().Allocate(IntPtr.Zero, (uint)bufferSize); // TODO: this is probably horribly inefficient Marshal.Copy(pAddr.ReadArray <byte>(bufferSize), 0, pBuffer, bufferSize); var pDisasmLoc = pBuffer; var virtualAddr = (uint)pAddr; // TODO: currently doesnt support x64 var disasm = new Disasm { EIP = pDisasmLoc, VirtualAddr = virtualAddr }; int length; var instructionsRead = 0; var bufferOffset = 0; while ((length = BeaEngine.Disasm(disasm)) != (int)BeaConstants.SpecialInfo.UNKNOWN_OPCODE) { instructionsRead++; var disasmInstr = new DisassemblyInstruction(disasm, length, virtualAddr.ReadArray <byte>(length)); yield return(disasmInstr); pDisasmLoc += length; virtualAddr += (uint)length; bufferOffset += length; if (maxInstructionCount > 0 && instructionsRead >= maxInstructionCount) { break; } // if we don't have an instruction limit and we're less than maxInstructionSize away // from the end of the buffer, reread buffer data from current location if ((bufferSize - bufferOffset) < maxInstructionSize) { // Copy new bytes to buffer from current location Marshal.Copy(virtualAddr.ReadArray <byte>(bufferSize), 0, pBuffer, bufferSize); // reset pointers etc pDisasmLoc = pBuffer; bufferOffset = 0; } disasm.EIP = pDisasmLoc; disasm.VirtualAddr = virtualAddr; } } finally { if (pBuffer != IntPtr.Zero) { Process.GetCurrentProcess().Free(pBuffer); } } }
public static IEnumerable<DisassemblyInstruction> Disassemble(IntPtr pAddr, int maxInstructionCount = 0) { if (pAddr == IntPtr.Zero) throw new ArgumentNullException("pAddr"); const int maxInstructionSize = 15; const int maxBufferSize = 4096; // default buffer of 100 x maxInstructionSize bytes (1500 bytes) // unless maxInstructionCount is specified var bufferSize = (maxInstructionCount == 0 ? 100 : maxInstructionCount)*maxInstructionSize; // ensure we don't allocate too large a buffer if a huge instruction count is specified bufferSize = Math.Min(bufferSize, maxBufferSize); // allocate an unmanaged buffer (instead of reading into managed byte array) var pBuffer = IntPtr.Zero; try { pBuffer = Process.GetCurrentProcess().Allocate(IntPtr.Zero, (uint) bufferSize); // TODO: this is probably horribly inefficient Marshal.Copy(pAddr.ReadArray<byte>(bufferSize), 0, pBuffer, bufferSize); var pDisasmLoc = pBuffer; var virtualAddr = (uint) pAddr; // TODO: currently doesnt support x64 var disasm = new Disasm {EIP = pDisasmLoc, VirtualAddr = virtualAddr}; int length; var instructionsRead = 0; var bufferOffset = 0; while ((length = BeaEngine.Disasm(disasm)) != (int) BeaConstants.SpecialInfo.UNKNOWN_OPCODE) { instructionsRead++; var disasmInstr = new DisassemblyInstruction(disasm, length, virtualAddr.ReadArray<byte>(length)); yield return disasmInstr; pDisasmLoc += length; virtualAddr += (uint) length; bufferOffset += length; if (maxInstructionCount > 0 && instructionsRead >= maxInstructionCount) break; // if we don't have an instruction limit and we're less than maxInstructionSize away // from the end of the buffer, reread buffer data from current location if ((bufferSize - bufferOffset) < maxInstructionSize) { // Copy new bytes to buffer from current location Marshal.Copy(virtualAddr.ReadArray<byte>(bufferSize), 0, pBuffer, bufferSize); // reset pointers etc pDisasmLoc = pBuffer; bufferOffset = 0; } disasm.EIP = pDisasmLoc; disasm.VirtualAddr = virtualAddr; } } finally { if (pBuffer != IntPtr.Zero) Process.GetCurrentProcess().Free(pBuffer); } }