Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Possiible access to DR6 register?

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting
View previous topic :: View next topic  
Author Message
GH*master
Expert Cheater
Reputation: 8

Joined: 10 Jan 2008
Posts: 149
Location: Russia

PostPosted: Sun Apr 30, 2017 2:34 am    Post subject: Possiible access to DR6 register? Reply with quote

We have registers DR0, DR1, DR2, DR3 contain linear addresses of four hardware breakpoints. One or more registers are used

I need to know what hardware breakpoints was executed at moment time.

The DR6 debug state register contains information about which of the breakpoints caused a particular debugging situation, and some other information.

Access to DR6 register possiible from Lua engine? Other solutions?

Thanks!

Code:
--[[
   Версия: 0.01.b1
   Выход из рутины до близжайшего цикла
]]--

mainAddress = 0x4DA9FEF0 -- 025B3818 -- адрес некоторого параметра в игре 0045B5A4
nextAddress = nil
is64bits = targetIs64Bit()

tableInstruction ={}
tableBreakpointsAddress ={}

-- Есть ли такой брейкпоинт в истории
function ContaintsBeakPoint(address)
   for i = 1, #tableBreakpointsAddress do
      if tableBreakpointsAddress[i] == address then
         return true
      end
   end
   return false
end
-- Возвращает адрес по ret
function GetNextAddressFromRET(address)
   if is64bits then
      nextAddress = readPointer(RSP)
   else
      nextAddress = readPointer(ESP)
   end
   return nextAddress
end
-- Возвращает адрес по Jmp
function GetNextAddressFromJMP(address)
   local disassembledstring = nil
   if is64bits then
      disassembledstring = disassemble(RIP)
   else
      disassembledstring = disassemble(EIP)
   end
   local _, opcode, _, _ = splitDisassembledString(disassembledstring)
   return GetAddressFromOpcode(opcode)
end
-- Перевод числа в битовую таблицу
function ToBits(num, bits)
   local t = {}
   for b = bits, 1, -1 do
      rest = math.fmod(num,2)
      t[b] = math.floor(rest)
      num = (num-rest)/2
   end   
   if num == 0 then return t else   return {'Not enough bits to represent this number'} end
end
-- Возвращает таблицу флагов
function GetEFLAGS()
   local bitsTable = ToBits(EFLAGS, 16)
   local tableEFLAGS =
   {
      OF = bitsTable[17-12],
      DF = bitsTable[17-11],
      SF = bitsTable[17-8],
      ZF = bitsTable[17-7],
      AF = bitsTable[17-5],
      PF = bitsTable[17-3],
      CF = bitsTable[17-1]
   }
   return tableEFLAGS   
end
-- Возвращает адрес из опкода jmp dword ptr [edi*4+07895D88] или jmp 07895D88
function GetAddressFromOpcode (opcode)

   local rightLine = string.match(opcode, '%S*%s*(%S*)')
   local isPointer = string.match(opcode, '%[')
   if isPointer then
      rightLine = string.match(opcode, '%[(.*)%]')
      --00454664 - 8B 83 60030000        - mov eax,[ebx+00000360]
      if string.match(opcode, 'eax') then rightLine = string.gsub(rightLine, 'eax', string.format('%X', EAX)) end
      if string.match(opcode, 'ebx') then rightLine = string.gsub(rightLine, 'ebx', string.format('%X', EBX)) end
      if string.match(opcode, 'ecx') then rightLine = string.gsub(rightLine, 'ecx', string.format('%X', ECX)) end
      if string.match(opcode, 'edx') then rightLine = string.gsub(rightLine, 'edx', string.format('%X', EDX)) end
      if string.match(opcode, 'esi') then rightLine = string.gsub(rightLine, 'esi', string.format('%X', ESI)) end
      if string.match(opcode, 'edi') then rightLine = string.gsub(rightLine, 'edi', string.format('%X', EDI)) end
      if string.match(opcode, 'esp') then rightLine = string.gsub(rightLine, 'esp', string.format('%X', ESP)) end
      if string.match(opcode, 'ebp') then rightLine = string.gsub(rightLine, 'ebp', string.format('%X', EBP)) end
      
      if is64bits then
         if string.match(opcode, 'rax') then rightLine = string.gsub(rightLine, 'rax', string.format('%X', RAX)) end
         if string.match(opcode, 'rbx') then rightLine = string.gsub(rightLine, 'rbx', string.format('%X', RBX)) end
         if string.match(opcode, 'rcx') then rightLine = string.gsub(rightLine, 'rcx', string.format('%X', RCXX)) end
         if string.match(opcode, 'rdx') then rightLine = string.gsub(rightLine, 'rdx', string.format('%X', RDX)) end
         if string.match(opcode, 'rsi') then rightLine = string.gsub(rightLine, 'rsi', string.format('%X', RSI)) end
         if string.match(opcode, 'rdi') then rightLine = string.gsub(rightLine, 'rdi', string.format('%X', RDI)) end
         if string.match(opcode, 'rsp') then rightLine = string.gsub(rightLine, 'rsp', string.format('%X', RSP)) end
         if string.match(opcode, 'rbp') then rightLine = string.gsub(rightLine, 'rbp', string.format('%X', RBP)) end
         
         if string.match(opcode, 'r8') then rightLine = string.gsub(rightLine, 'r8', string.format('%X', R8)) end
         if string.match(opcode, 'r9') then rightLine = string.gsub(rightLine, 'r9', string.format('%X', R9)) end
         if string.match(opcode, 'r10') then rightLine = string.gsub(rightLine, 'r10', string.format('%X', R10)) end
         if string.match(opcode, 'r11') then rightLine = string.gsub(rightLine, 'r11', string.format('%X', R11)) end
         if string.match(opcode, 'r12') then rightLine = string.gsub(rightLine, 'r12', string.format('%X', R12)) end
         if string.match(opcode, 'r13') then rightLine = string.gsub(rightLine, 'r13', string.format('%X', R13)) end
         if string.match(opcode, 'r14') then rightLine = string.gsub(rightLine, 'r14', string.format('%X', R14)) end
         if string.match(opcode, 'r15') then rightLine = string.gsub(rightLine, 'r15', string.format('%X', R15)) end
      end
      
      return getAddress('['..rightLine..']')
   else
      if string.match(opcode, 'eax') then rightLine = string.gsub(rightLine, 'eax', string.format('%X', EAX)) end
      if string.match(opcode, 'ebx') then rightLine = string.gsub(rightLine, 'ebx', string.format('%X', EBX)) end
      if string.match(opcode, 'ecx') then rightLine = string.gsub(rightLine, 'ecx', string.format('%X', ECX)) end
      if string.match(opcode, 'edx') then rightLine = string.gsub(rightLine, 'edx', string.format('%X', EDX)) end
      if string.match(opcode, 'esi') then rightLine = string.gsub(rightLine, 'esi', string.format('%X', ESI)) end
      if string.match(opcode, 'edi') then rightLine = string.gsub(rightLine, 'edi', string.format('%X', EDI)) end
      if string.match(opcode, 'esp') then rightLine = string.gsub(rightLine, 'esp', string.format('%X', ESP)) end
      if string.match(opcode, 'ebp') then rightLine = string.gsub(rightLine, 'ebp', string.format('%X', EBP)) end
      
      if is64bits then
         if string.match(opcode, 'rax') then rightLine = string.gsub(rightLine, 'rax', string.format('%X', RAX)) end
         if string.match(opcode, 'rbx') then rightLine = string.gsub(rightLine, 'rbx', string.format('%X', RBX)) end
         if string.match(opcode, 'rcx') then rightLine = string.gsub(rightLine, 'rcx', string.format('%X', RCXX)) end
         if string.match(opcode, 'rdx') then rightLine = string.gsub(rightLine, 'rdx', string.format('%X', RDX)) end
         if string.match(opcode, 'rsi') then rightLine = string.gsub(rightLine, 'rsi', string.format('%X', RSI)) end
         if string.match(opcode, 'rdi') then rightLine = string.gsub(rightLine, 'rdi', string.format('%X', RDI)) end
         if string.match(opcode, 'rsp') then rightLine = string.gsub(rightLine, 'rsp', string.format('%X', RSP)) end
         if string.match(opcode, 'rbp') then rightLine = string.gsub(rightLine, 'rbp', string.format('%X', RBP)) end
         
         if string.match(opcode, 'r8') then rightLine = string.gsub(rightLine, 'r8', string.format('%X', R8)) end
         if string.match(opcode, 'r9') then rightLine = string.gsub(rightLine, 'r9', string.format('%X', R9)) end
         if string.match(opcode, 'r10') then rightLine = string.gsub(rightLine, 'r10', string.format('%X', R10)) end
         if string.match(opcode, 'r11') then rightLine = string.gsub(rightLine, 'r11', string.format('%X', R11)) end
         if string.match(opcode, 'r12') then rightLine = string.gsub(rightLine, 'r12', string.format('%X', R12)) end
         if string.match(opcode, 'r13') then rightLine = string.gsub(rightLine, 'r13', string.format('%X', R13)) end
         if string.match(opcode, 'r14') then rightLine = string.gsub(rightLine, 'r14', string.format('%X', R14)) end
         if string.match(opcode, 'r15') then rightLine = string.gsub(rightLine, 'r15', string.format('%X', R15)) end
      end
   end
   
   return getAddress(rightLine)
end
-- Возвращает адрес по Jmp condition, когда тот выполняется или не выполняется
function GetNextAddressFromConditionJMP(address, size)

   local _,opcode,_,_ = splitDisassembledString(disassemble(address))
   local leftString = string.match(opcode, '%S*')
   local eflags = GetEFLAGS()
   
   if (leftString == 'jnz' or leftString == 'jne')    then
      if eflags.ZF == 0  then
         return GetAddressFromOpcode(opcode)
      end
      elseif (leftString == 'je' or leftString == 'jz')    then
         if eflags.ZF == 1 then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jg' or leftString == 'jnle')   then
         if eflags.ZF == 0 and eflags.SF == eflags.OF then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jb' or leftString == 'jc' or leftString == 'jnae') then
         if eflags.CF == 1  then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jae') then
         if eflags.CF == 0 then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'ja') then
         if eflags.CF == 0 and eflags.ZF == 0 then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jbe') then
         if eflags.CF == 1 and eflags.ZF == 1 then
            return GetAddressFromOpcode(opcode)
         end   
      elseif (leftString == 'jl' or leftString == 'jnge') then
         if eflags.SF ~= eflags.OF then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jle' or leftString == 'jng')   then
         if eflags.ZF == 1 or eflags.SF ~= eflags.OF  then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jna') then
         if eflags.CF == 1 or eflags.ZF == 1
            then return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jc')   then
         if eflags.CF == 1 then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jp' or leftString == 'jpe') then
         if eflags.PF == 1 then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jnp' or leftString == 'jpo')then
         if eflags.PF == 0 then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jnb' or leftString == 'jnc') then
         if eflags.CF == 0 then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jnbe')  then
         if eflags.CF == 0 and eflags.ZF == 0 then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jno') then
         if eflags.OF == 0 then
            return GetAddressFromOpcode(opcode)
         end   
      elseif (leftString == 'jns') then
         if eflags.SF == 0 then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jo') then
         if eflags.OF == 1 then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'js') then
         if eflags.SF == 1 then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jge' or leftString == 'jnl') then
         if eflags.CF == 1 and eflags.OF == 1 then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jrcxz')    then
         if RCX == 0 then
            return GetAddressFromOpcode(opcode)
         end
      elseif (leftString == 'jecxz') then
         if ECX == 0 then
            return GetAddressFromOpcode(opcode)
         end
   end
   return address + size
end
-- Это ret инструкция?
function IsRet(address)
   local value = readBytes(address,1, false)
   return value == 0xC3 or value == 0xCB or  value == 0xC2 or value == 0xCA
end

   --    -- Это call инструкция?
   --    function IsCall(address)
   --    local value = readBytes(address,1, false)
   --    return value == 0xFF or value == 0xE8 -- or  value == 0x9A
   --    end
   
-- Это jmp инструкция?
function IsJMP(address)
   local value = readBytes (address, 1, false)
   
   -- Исключенеие не подходщих инструкций по первому байту FF и следующему за ним
   if value == 0xFF then
      local nextByte = readBytes (address + 1, 1, false)
      if  nextByte == 0x05 or   nextByte == 0x15 or
         nextByte == 0x50 or   nextByte == 0x70 or
         nextByte == 0x30 or nextByte == 0x75  then
         return false
      end
   end
--[[
   078921A8 - EB 38                       - jmp 078921E2
   0789242D - E9 E2000000              - jmp 07892514
   07894F4C - FF E2                          - jmp edx
   07895C67 - FF 24 BD 885D8907     - jmp dword ptr [edi*4+07895D88]
]]--      
   return value == 0xEB or value == 0xE9 or  value == 0xFF -- or value == 0xEA
end
-- Это jmp condition инструкция?
function IsConditionJMP(address)
   local value = readBytes (address, 1, false)
   return 
      value == 0x77 or value == 0x73 or value == 0x72 or value == 0x76 or
      value == 0xE3 or value == 0x74 or value == 0x7F or value == 0x7D or
      value == 0x7C or value == 0x7E or value == 0x75 or value == 0x71 or
      value == 0x7B or value == 0x79 or value == 0x70 or value == 0x7A or
      value == 0x78 or value == 0x0F
end

-- Возвращает адрес на который, будет переход
function GetNextAddress(addressXIP)
   -- Определить на какой инструкции мы находимся, чтобы узнать на какую следующу инструкцию ставить бряк
   -- ret            - прыжок по смещению ESP/RSP
   -- jmp            - прыжок без условия
   -- je, jne, jxx   - прыжок с улосвием
   
   -- Определить размер инструкции, тип инструкции на текущем addressXIP
   local findIndex = -1
   for i = 1, #tableInstruction do
      if tableInstruction[i].XIP == addressXIP then
         findIndex = i
         break
      end
   end
   
   local size = 0
   local isRet = false
   local isJMP = false
   local isCJMP = false
      
   if findIndex ==  -1 then
      -- Если нет данных
      ---------------- ЗАПОМИНАТЬ РАЗМЕР ИНСТРУКЦИИ (чтобы не дизассемблировать повторно)
      size = getInstructionSize(addressXIP)
      isRet = IsRet(addressXIP)
      isJMP = IsJMP(addressXIP)
      isCJMP = IsConditionJMP(addressXIP)
      table.insert(tableInstruction, {XIP = addressXIP, SIZE = size, ISRET = isRet, ISJMP = isJMP,  ISCJMP = isCJMP})
   else
      -- Если данные есть
      size = tableInstruction[findIndex].SIZE
      isRet = tableInstruction[findIndex].ISRET
      isJMP = tableInstruction[findIndex].ISJMP
      isCJMP = tableInstruction[findIndex].ISCJMP
   end   
   ---------------
   
   if isRet then
      local storyAddress = nextAddress
      nextAddress = GetNextAddressFromRET(addressXIP)
      print('> RET   :' ..disassemble(storyAddress)..AddSpace('   -->>   :' ..disassemble(nextAddress)))
   elseif isJMP then
      --local storyAddress = nextAddress
      nextAddress =  GetNextAddressFromJMP(addressXIP)
      --print('> isJMP   :' ..disassemble(storyAddress)..AddSpace('   -->>   :' ..disassemble(nextAddress)))
   elseif isCJMP then
      --local storyAddress = nextAddress
      nextAddress = GetNextAddressFromConditionJMP(addressXIP, size)
      --print('> isCJMP   :' ..disassemble(storyAddress)..AddSpace('   -->>   :' ..disassemble(nextAddress)))
   else
      nextAddress = addressXIP + size
   end
   
   return nextAddress
end

function AddSpace(line)
   return line..string.rep (' ', 80 - string.len(line))
end

function debugger_onBreakpoint()

   local isContaintsBreakPoint = false
   
   -- Удалить прошлый брейкпоинт
   if(nextAddress ~= nil) then
      isContaintsBreakPoint = ContaintsBeakPoint(nextAddress)
      if isContaintsBreakPoint then
         debug_removeBreakpoint(nextAddress)
      end
   end   
   
   -- Поставить брейкпоинт на следующую инструкцию не входя в call-ы
   local XIP = 0
   if is64bits then XIP = EIP else XIP = RIP end
   
   nextAddress = GetNextAddress(XIP)
   
   -- Нельзя ставить брейкпоинт на адресс повторно
   if not ContaintsBeakPoint(nextAddress) then
      debug_setBreakpoint(nextAddress, 1, bptExecute, bpmDebugRegister)
      table.insert(tableBreakpointsAddress, nextAddress)
   end
   
   return 1 --1 не показывать дизассемблер
end

if getOpenedProcessID() == 0 then
   --openProcess('DebugStep.exe')
   openProcess('xrEngine.exe')
end


--bptWrite
--bptAccess
--debug_removeBreakpoint()
debug_setBreakpoint(mainAddress, 4, bptAccess, bpmDebugRegister)
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 338

Joined: 09 May 2003
Posts: 19830
Location: The netherlands

PostPosted: Sun Apr 30, 2017 4:19 am    Post subject: Reply with quote

instead of using function debugger_onBreakpoint() you can also use

debug_setBreakpoint(mainAddress, 4, bptAccess, bpmDebugRegister, functiontocallonbp)

that will be unique for that specific breakpoint

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Back to top
View user's profile Send private message MSN Messenger
GH*master
Expert Cheater
Reputation: 8

Joined: 10 Jan 2008
Posts: 149
Location: Russia

PostPosted: Sun Apr 30, 2017 4:55 am    Post subject: Reply with quote

Oh sure. Idea Razz I forgot about this functiontocall

Quote:
debug_setBreakpoint(address, size OPTIONAL, trigger OPTIONAL, breakpointmethod OPTIONAL, functiontocall() OPTIONAL) : sets a breakpoint of a specific size at the given address. if trigger is bptExecute then size is ignored. If trigger is ignored then it will be of type bptExecute, which obviously also ignores the size then as well


Thanks, I'll try this function
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites