Jump to content
Tuts 4 You

Debug Registers


snoopy

Recommended Posts

Hey guys,


 


I am reading up on ARteam securom information.


 


What I am wondering is the following.


 


Deroko in his post is posting a  method to set hardware breakpoints to work his way around with the code splicing.


 


What I am mis understanding is the following code from the goodies dir there is vmtrace.asm.


 


In here he sets Dr0 with the following info:


 


mov [ecx.context_dr0], eax          //eax reg hold the address to breakpoint


mov [ecx.context_dr7], 10101h   //should be a breakpoint on write


 


What I am missing here is how did he calculate 10101h.


 


According to the intel manual, there is 31 bits:


 


 


19  18  17   16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0    BITS


 


0     0   1     0    0    0  0   0   0   1  0 0 0 0 0 0 0 0 1 0


 


LE  LE RW RW                                    3 3 2 2 1 1 0 0    DEBUG REGS


 


Based on the above I am doing the following:


 


I set bit 1 to enable global breakpoint for debug register 0


 


Than I set 0 to the other bits till 10, according to the intel manual bit 10 should be 1.


 


Bits 11 - 15 are set to 0


 


Bit 16 and 17 describes what type of breakpoint to set


According to the intel manual:


00 break on execution


01 break on write                  //Bit 16 = 0 - Bit 17 = 1?


10 break on read/ write


11 break on read/ write


 


Than bit 18 and 19 describe the size:


According to intel manual:


00 1 byte                             //Bit 18 = 0 - Bit 19 = 0 to tell 1 byte?


01 2 bytes


10 undefined/ 8 bytes


11 4 bytes


 


based on the above my results = 20402h


 


What am I missing here? as my breakpoint isn't triggered either, it only works when setting 10101h and I have no idea why.


 


Could someone explain to me how to work with these.


 


Thanks in advance.


Link to comment

evlncrn8 the result from deroko = 10000000100000001 -> converted to hexadecimal as 10101h


 


My result = 100000010000000010 -> converted to hexadecimal as 20402h.


 


I have no idea why I am not getting the result he is getting.


It looks like he is setting lesser bits or I am missing an important thing here.


Link to comment

Some time ago I wrote a usable hardware breakpoint structure + conversion to uint and vice-versa, so I decided to extend the thing a little.

Using this code (c++):

#include <stdio.h>#include <windows.h>enum HWBP_MODE{    MODE_DISABLED=0, //00    MODE_LOCAL=1, //01    MODE_GLOBAL=2 //10};enum HWBP_TYPE{    TYPE_EXECUTE=0, //00    TYPE_WRITE=1, //01    TYPE_READWRITE=3 //11};enum HWBP_SIZE{    SIZE_1=0, //00    SIZE_2=1, //01    SIZE_8=2, //10    SIZE_4=3 //11};struct DR7{    BYTE HWBP_MODE[4];    BYTE HWBP_TYPE[4];    BYTE HWBP_SIZE[4];};#define BITSET(a,x) (a|=1<<x)#define BITCLEAR(a,x) (a&=~(1<<x))#define BITTOGGLE(a,x) (a^=1<<x)#define BITGET(a,x) (a&(1<<x))ULONG_PTR dr7uint(DR7* dr7){    ULONG_PTR ret=0;    if(BITGET(dr7->HWBP_MODE[0],0))        BITSET(ret,0);    if(BITGET(dr7->HWBP_MODE[0],1))        BITSET(ret,1);    if(BITGET(dr7->HWBP_MODE[1],0))        BITSET(ret,2);    if(BITGET(dr7->HWBP_MODE[1],1))        BITSET(ret,3);    if(BITGET(dr7->HWBP_MODE[2],0))        BITSET(ret,4);    if(BITGET(dr7->HWBP_MODE[2],1))        BITSET(ret,5);    if(BITGET(dr7->HWBP_MODE[3],0))        BITSET(ret,6);    if(BITGET(dr7->HWBP_MODE[3],1))        BITSET(ret,7);    if(BITGET(dr7->HWBP_TYPE[0],0))        BITSET(ret,16);    if(BITGET(dr7->HWBP_TYPE[0],1))        BITSET(ret,17);    if(BITGET(dr7->HWBP_SIZE[0],0))        BITSET(ret,18);    if(BITGET(dr7->HWBP_SIZE[0],1))        BITSET(ret,19);    if(BITGET(dr7->HWBP_TYPE[1],0))        BITSET(ret,20);    if(BITGET(dr7->HWBP_TYPE[1],1))        BITSET(ret,21);    if(BITGET(dr7->HWBP_SIZE[1],0))        BITSET(ret,22);    if(BITGET(dr7->HWBP_SIZE[1],1))        BITSET(ret,23);    if(BITGET(dr7->HWBP_TYPE[2],0))        BITSET(ret,24);    if(BITGET(dr7->HWBP_TYPE[2],1))        BITSET(ret,25);    if(BITGET(dr7->HWBP_SIZE[2],0))        BITSET(ret,26);    if(BITGET(dr7->HWBP_SIZE[2],1))        BITSET(ret,27);    if(BITGET(dr7->HWBP_TYPE[3],0))        BITSET(ret,28);    if(BITGET(dr7->HWBP_TYPE[3],1))        BITSET(ret,29);    if(BITGET(dr7->HWBP_SIZE[3],0))        BITSET(ret,30);    if(BITGET(dr7->HWBP_SIZE[3],1))        BITSET(ret,31);    return ret;}void uintdr7(ULONG_PTR dr7, DR7* ret){    memset(ret, 0, sizeof(DR7));    if(BITGET(dr7,0))        BITSET(ret->HWBP_MODE[0],0);    if(BITGET(dr7,1))        BITSET(ret->HWBP_MODE[0],1);    if(BITGET(dr7,2))        BITSET(ret->HWBP_MODE[1],0);    if(BITGET(dr7,3))        BITSET(ret->HWBP_MODE[1],1);    if(BITGET(dr7,4))        BITSET(ret->HWBP_MODE[2],0);    if(BITGET(dr7,5))        BITSET(ret->HWBP_MODE[2],1);    if(BITGET(dr7,6))        BITSET(ret->HWBP_MODE[3],0);    if(BITGET(dr7,7))        BITSET(ret->HWBP_MODE[3],1);    if(BITGET(dr7,16))        BITSET(ret->HWBP_TYPE[0],0);    if(BITGET(dr7,17))        BITSET(ret->HWBP_TYPE[0],1);    if(BITGET(dr7,18))        BITSET(ret->HWBP_SIZE[0],0);    if(BITGET(dr7,19))        BITSET(ret->HWBP_SIZE[0],1);    if(BITGET(dr7,20))        BITSET(ret->HWBP_TYPE[1],0);    if(BITGET(dr7,21))        BITSET(ret->HWBP_TYPE[1],1);    if(BITGET(dr7,22))        BITSET(ret->HWBP_SIZE[1],0);    if(BITGET(dr7,23))        BITSET(ret->HWBP_SIZE[1],1);    if(BITGET(dr7,24))        BITSET(ret->HWBP_TYPE[2],0);    if(BITGET(dr7,25))        BITSET(ret->HWBP_TYPE[2],1);    if(BITGET(dr7,26))        BITSET(ret->HWBP_SIZE[2],0);    if(BITGET(dr7,27))        BITSET(ret->HWBP_SIZE[2],1);    if(BITGET(dr7,28))        BITSET(ret->HWBP_TYPE[3],0);    if(BITGET(dr7,29))        BITSET(ret->HWBP_TYPE[3],1);    if(BITGET(dr7,30))        BITSET(ret->HWBP_SIZE[3],0);    if(BITGET(dr7,31))        BITSET(ret->HWBP_SIZE[3],1);}int main(){    printf("size: %d\n", sizeof(DR7));    DR7 dr7;    memset(&dr7, 0, sizeof(DR7));    dr7.HWBP_MODE[0]=MODE_GLOBAL; //enable hardware breakpoint    dr7.HWBP_SIZE[0]=SIZE_4; //dword    dr7.HWBP_TYPE[0]=TYPE_READWRITE; //readwrite    ULONG_PTR dr7_=dr7uint(&dr7);    printf("dr7: %X\n", dr7_);    DR7 test;    uintdr7(dr7_, &test);    if(!memcmp(&test, &dr7, sizeof(DR7)))        puts("good!");    ULONG_PTR deroko=0x10101;    uintdr7(deroko, &test);    char* modes[]= {"MODE_DISABLED","MODE_LOCAL","MODE_GLOBAL"};    char* types[]= {"TYPE_EXECUTE","TYPE_WRITE","TYPE_IO","TYPE_READWRITE"};    char* sizes[]= {"SIZE_1","SIZE_2","SIZE_8","SIZE_4"};    for(int i=0; i<4; i++)        printf("HWBP%d:%s,%s,%s\n", i+1, modes[test.HWBP_MODE[i]], types[test.HWBP_SIZE[i]], sizes[test.HWBP_TYPE[i]]);    memset(&dr7, 0, sizeof(DR7));    dr7.HWBP_MODE[0]=MODE_GLOBAL; //enable hardware breakpoint    dr7.HWBP_SIZE[0]=SIZE_8; //dword    dr7.HWBP_TYPE[0]=TYPE_READWRITE; //readwrite    printf("dr7: %.16llX\n", dr7uint(&dr7)); //11110000000000000010    return 0;}
Prints me:
HWBP1:MODE_LOCAL,TYPE_EXECUTE,SIZE_2HWBP2:MODE_DISABLED,TYPE_EXECUTE,SIZE_1HWBP3:MODE_DISABLED,TYPE_EXECUTE,SIZE_1HWBP4:MODE_DISABLED,TYPE_EXECUTE,SIZE_1
So you're setting a local hardware breakpoint (that's OK), on execute with size 2 (which is ignore iirc)

Also notice, that the code you provided:

mov [ecx.context_dr0], eax          //eax reg hold the address to breakpointmov [ecx.context_dr7], 10101h   //should be a breakpoint on write
will NOT work work x64, you should first set dr7 and then dr0 (otherwise dr0 gets reset):
mov [ecx.context_dr7], 10101h   //should be a breakpoint on writemov [ecx.context_dr0], eax          //eax reg hold the address to breakpoint
Seems like deroko made a small mistake in his paper..

EDIT: 0x10001 is the result of, so you should use that:

dr7.HWBP_MODE[0]=MODE_LOCAL; //enable hardware breakpointdr7.HWBP_SIZE[0]=SIZE_1; //byte+word+dword(+qword)dr7.HWBP_TYPE[0]=TYPE_WRITE; //write
Edited by Mr. eXoDia
Link to comment

will NOT work work x64, you should first set dr7 and then dr0 (otherwise dr0 gets reset):

 

what do you mean? you're only modifying a struct in memory, as long as you call SetContext() only once, you'll be fine.

Also, writing to a dr register does not have any sideeffects on other dr registers, to my knowledge (x86 and x64).

 

 

merry christmas, btw! :)

Link to comment

Mr_Exodia,


 


Thanks for the information.


I am trying to do it in ASM, will see what I can make out of this C++ information.


Atm the results still don't make sense to me, and all the results are giving me are stack overflows (as the breakpoint is never triggered).


 


So: 10001 = the right result, but I still don't understand how to calculate them manually by setting the bits.


 


 


Link to comment
10001

(hex)

 

would set a data breakpoint on the address in DR0, local, on write for one byte.

 

The breakpoint would not work if

 

* there is no valid address in DR0

* the address is only read, not written to

 

 

as to the why:

 

 

 

VAs: DR0,DR1,DR2,DR3

Invalid: DR4,Dr5

Status: DR6

Flags: DR7

Bits     Meaning

0-7     

        Flags for each of the 4 debug registers (2 for each).

        The first flag is set to specify a local breakpoint (so the CPU resets the flag when switching tasks),

        and the second flag is set to specify a global breakpoint.

        

16-23     

        2 bits for each register, defining when the breakpoint will be triggered:

        00b - Triggers when code is executed

        01b - Triggers when data is written

        10b - Reserved

        11b - Triggers when data is read or written

24-31     

        2 bits for each register, defining the size of the breakpoint:

        00b - 1 byte

        01b - 2 bytes

        10b - 8 bytes

        11b - 4 bytes

10001hex == 1-0000-0000-0000-0001bin

 

The rightmost flag (position 0) enabes a local breakpoint for DR0.

The leftmost flag (position 17) specifies "data written".

The 24th bit (not written) is zero and specifies "1 byte size".

Link to comment

what do you mean? you're only modifying a struct in memory, as long as you call SetContext() only once, you'll be fine.

Also, writing to a dr register does not have any sideeffects on other dr registers, to my knowledge (x86 and x64).

 

 

merry christmas, btw! :)

Merry Christmas to you too!

Here is a video to show what I mean, not setting dr7 sort of 'locks' the dr0 register... But you're indeed right about the structure part, in this case it doesn't matter..

x64_dr7.rar

Edited by Mr. eXoDia
Link to comment
  • 4 months later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...