public static void SetFlag(this Win64.CONTEXT ctx, NIContextFlag i, bool value) { ctx.EFlags -= ctx.GetFlag(i) ? (uint)i : 0; ctx.EFlags ^= (value) ? (uint)i : 0; }
/// <summary> /// Performs a SingleStep operation, that is to stay it resumes the process and pauses at the very next instruction. /// Jumps are followed, conditional jumps are evaluated, Calls are either stepped into or over depending on StepIntoCalls value. /// </summary> /// <returns></returns> public NIDebugger64 SingleStep() { getContext(getCurrentThreadId()); ulong address = Context.Rip; if (address == 0x7ffa79b6660e) { int i = 0; } byte[] data; ReadData(address, 16, out data); if (breakpoints.ContainsKey(address) == true) { Array.Copy(breakpoints[address].originalBytes, data, 2); ClearBreakpoint(address); } ldasm_data ldata = lde.ldasm(data, 0, false); uint size = ldata.size; ulong nextAddress = Context.Rip + size; if (ldata.opcd_size == 1 && (data[ldata.opcd_offset] == 0xEB)) { // we have a 1 byte JMP here sbyte offset = (sbyte)data[ldata.imm_offset]; nextAddress = (ulong)((long)Context.Rip + offset) + ldata.size; } if ((data[ldata.opcd_offset] == 0xE2)) { // LOOP if (Context.Rcx == 1) { // this instruction will make ECX 0, so we fall thru the jump now nextAddress = (ulong)((long)Context.Rip + ldata.size); } else if (Context.Rcx > 1) { // this instruction will decrement ECX but it wont be 0 yet, so jump! sbyte disp = (sbyte)data[1]; nextAddress = (uint)((long)Context.Rip + disp) + ldata.size; } } if ((data[ldata.opcd_offset] == 0xE0)) { //LOOPNZ LOOPNE if (Context.Rcx == 1 && Context.GetFlag(NIContextFlag.ZERO) == false) { nextAddress = (ulong)((long)Context.Rip + ldata.size); } else if (Context.Rcx > 1 || Context.GetFlag(NIContextFlag.ZERO) != false) { sbyte disp = (sbyte)data[1]; nextAddress = (ulong)((long)Context.Rip + disp) + ldata.size; } } if ((data[ldata.opcd_offset] == 0xE1)) { //LOOPZ LOOPE if (Context.Rcx == 1 && Context.GetFlag(NIContextFlag.ZERO) == true) { nextAddress = (ulong)((long)Context.Rip + ldata.size); } else if (Context.Rcx > 1 || Context.GetFlag(NIContextFlag.ZERO) != true) { sbyte disp = (sbyte)data[1]; nextAddress = (ulong)((long)Context.Rip + disp) + ldata.size; } } if (ldata.opcd_size == 1 && ((data[ldata.opcd_offset] == 0xE9) || (data[ldata.opcd_offset] == 0xE8))) { // we have a long JMP or CALL here int offset = BitConverter.ToInt32(data, ldata.imm_offset); if ((data[ldata.opcd_offset] == 0xE9) || (StepIntoCalls && (data[ldata.opcd_offset] == 0xE8))) { nextAddress = (ulong)((long)Context.Rip + offset) + ldata.size; } } if (ldata.opcd_size == 1 && ((data[ldata.opcd_offset] >= 0x70 && (data[ldata.opcd_offset] <= 0x7F)) || (data[ldata.opcd_offset] == 0xE3))) { // we have a 1byte jcc here bool willJump = evalJcc(data[ldata.opcd_offset]); if (willJump) { sbyte offset = (sbyte)data[ldata.imm_offset]; nextAddress = (ulong)((long)Context.Rip + offset) + ldata.size; } } if (ldata.opcd_size == 2 && ((data[ldata.opcd_offset] == 0x0F) || (data[ldata.opcd_offset + 1] == 0x80))) { // we have a 2 byte jcc here bool willJump = evalJcc(data[ldata.opcd_offset + 1]); if (willJump) { int offset = BitConverter.ToInt32(data, ldata.imm_offset); nextAddress = (ulong)(((long)Context.Rip + offset) + ldata.size); } } if (data[ldata.opcd_offset] == 0xC3 || data[ldata.opcd_offset] == 0xC2) { ReadStackValue(0, out nextAddress); } if (data[ldata.opcd_offset] == 0xFF && ldata.opcd_size == 1 && ldata.modrm != 0x00) { // let's parse ModRM! var reg2 = (ldata.modrm & 0x38) >> 3; var mod = (ldata.modrm & 0xC0) >> 6; var reg1 = (ldata.modrm & 0x7); bool addressSet = false; if (reg2 == 2) { if (StepIntoCalls == false) { nextAddress = (uint)Context.Rip + ldata.size; addressSet = true; } Console.Write("RegOp tells me this is a CALL\r\n"); } else if (reg2 == 4) { Console.Write("RegOp tells me this is a JMP\r\n"); } else { nextAddress = (uint)Context.Rip + ldata.size; addressSet = true; } if (addressSet == false) { if (reg1 == 4) { //txtFacts.Text += "Reg1 is a 4 which means there is a SIB byte\r\n"; var ss = (ldata.sib & 0xC0) >> 6; var index = (ldata.sib & 0x38) >> 3; var Base = (ldata.sib & 0x07); int scale = (int)Math.Pow(2, ss); nextAddress = (uint)GetRegisterByNumber(index) * (uint)scale; if (Base == 5) { if (mod == 0) { nextAddress = (uint)((int)nextAddress + BitConverter.ToInt32(data, ldata.disp_offset)); } else if (mod == 1) { nextAddress += GetRegisterByNumber(Base); nextAddress = (uint)((int)(nextAddress) + (sbyte)data[ldata.disp_offset]); } else if (mod == 2) { nextAddress += GetRegisterByNumber(Base); nextAddress = (uint)((int)nextAddress + BitConverter.ToInt32(data, ldata.disp_offset)); } } } else { if (mod == 0) { if (reg1 != 5) { nextAddress = GetRegisterByNumber(reg1); } else { nextAddress = (uint)BitConverter.ToInt32(data, ldata.disp_offset); } } else if (mod == 1) { nextAddress = GetRegisterByNumber(reg1); nextAddress = (uint)((int)(nextAddress) + (sbyte)data[ldata.disp_offset]); } else if (mod == 2) { nextAddress = GetRegisterByNumber(reg1); nextAddress = (uint)((int)nextAddress + BitConverter.ToInt32(data, ldata.disp_offset)); } } if (mod != 3) { //ReadDWORD(nextAddress, out nextAddress); } Console.WriteLine("Next Address: " + nextAddress.ToString("X8")); } } updateContext(getCurrentThreadId()); SetBreakpoint(nextAddress); Continue(); ClearBreakpoint(nextAddress); return(this); }