Jump to content
Tuts 4 You

[Help] INT3 detection and patching


ding

Recommended Posts

Posted (edited)

Hello everyone , hope you all are doing well .

I was reading a book called ' The art of unpacking ' , on the page 13 the author was talking about both software and hardware breakpoint detection and patching techniques .

This is a preview of what was written :


 spacer.png

 

The code is clear except (protected code start) and (protected code end) . I guess the first one is referring to the address of entry point  of the target application ? if so , How can I determine the end of the code ? 

I wanted to include this method in my application which is written in delphi ( for testing purpose ) but I couldn't do it , Any piece of code will be more than welcome . 

So many questions are going through my brain , The  memory of the target executable doesn't contain only one byte with the value '$CC' , when patching the byte in a random way that could affect other bytes in the memory as well , am I right ? 

Hope someone help me with this matter , Any solution in ( delphi - assembly ) is accepted .

greeting

 

 

Edited by ding
Posted (edited)

anyone please ? 

I read about hooking the interrupt descriptor table ,which is similar to what i want to do but it needs some skills in (C and driver programming) which i don't have, Any ideas ?

Am not asking for something ready , any link will be useful .

Regards

Edited by ding
Posted

When a debugger sets a Softwarebreakpoint, it writes the opcode-byte 0xCC to the address where the breakpoint is set.

Thus, a way to scan and detect breakpoints is to compare the first by of all the instructions you want to protect against breakpoints to 0xCC - if you find one, you found a breakpoint.

In the example, protected_code_start and _end refer to the limits of the code you are scanning. This could be the start and end of a critical function you wish to protect.

 

The code is bad though: it blindly compares ALL bytes in range against 0xCC, whereas you should  compare the first byte of each instruction  only. Longer instructions might contain legitimate 0xCC bytes as data. Consider mov al, 0xCC ==> b0 cc .

 

 

IDT hooking is something completely different.

  • Like 1
Posted (edited)
5 hours ago, deepzero said:

The code is bad though: it blindly compares ALL bytes in range against 0xCC, whereas you should  compare the first byte of each instruction  only. Longer instructions might contain legitimate 0xCC bytes as data. Consider mov al, 0xCC ==> b0 cc .

Hello , 

Thank you so much for clarifying all the informations above , I understand from what you've said that there is no way to protect all the code section agaist software breakpoints ? 

suppose i have this function  : 

function check_credentials(user : string; pass : string):boolean;
begin
  if (user <> 'User') and (pass <> 'S3cret') then
  begin
   showmessage('Wrong Credentials');
   end else
   showmessage('Congratulations');
   result := true;
end;

How can i determine the start and the end of this function ? 

I'll read again about IDT Hooking and try to dive deeper to fully understand what it means .

Once again thanks for helping me out .

Ding

Edited by ding
Posted

 

Quote

, I understand from what you've said that there is no way to protect all the code section agaist software breakpoints ? 

You could also do that for the whole code section, however you have to be very careful as to
1) disassemble everything correctly, in order not to run into the same problem as before, where the 0xCC occurs as data in a legitimate instruction

2) padding might use 0xCC as filler bytes.

Especially Delphi also likes to embedd data in the code section, so you cannot just do a linear assembly and compare the first byte. your dissassemler would be thrown off by embedded data or padding.
in practice, there is no good way here.

Quote

How can i determine the start and the end of this function ? 

I dont know how to do this in Delphi. You'd start by getting a method pointer and pass that to ReadMemory WinApi. No idea how to get the size of the method or how to do it concretely.

Generally I think C or C++ is more straight forward for this kind of lowlevel stuff ... in my opinion.

  • Thanks 1
Posted
3 hours ago, ding said:

suppose i have this function  : 


function check_credentials(user : string; pass : string):boolean;
begin
  if (user <> 'User') and (pass <> 'S3cret') then
  begin
   showmessage('Wrong Credentials');
   end else
   showmessage('Congratulations');
   result := true;
end;

How can i determine the start and the end of this function ? 

Hi

Finding start point of function is easy, you just need do something like this :

var
  StartAddr : Pointer;
begin
  StartAddr := @check_credentials;

But for finding end of function, there is several ways:

1) search for "RET" instruction (C3, C2 xx) but if you're using "try/finally/except" statement your function will have several "RET(C3)" instruction.

2) You can define dummy function right after your function and get it's start address as end of your function !

function check_credentials(user : string; pass : string):boolean;
begin
  if (user <> 'User') and (pass <> 'S3cret') then
  begin
   showmessage('Wrong Credentials');
   end else
   showmessage('Congratulations');
   result := true;
end;

procedure Dummy; assembler;
asm
end;

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  StartAddr, EndAddr : Pointer;
begin
  StartAddr := @check_credentials;
  EndAddr := @Dummy;

  Caption := IntToHex(NativeUInt(EndAddr) - NativeUInt(StartAddr));  //will get size of your function in byte (+1 byte for Dummy function)
end;

 

BR,

h4sh3m

  • Like 2
Posted
2 hours ago, h4sh3m said:

1) search for "RET" instruction (C3, C2 xx) but if you're using "try/finally/except" statement your function will have several "RET(C3)" instruction.

2) You can define dummy function right after your function and get it's start address as end of your function !

BR,

h4sh3m

Hi h4sh3m , Thanks for your reply 

for some reason this code still doesn't work ! When I hit the check button the application exits even if it's not under any debugger .

procedure TForm1.Button1Click(Sender: TObject);
var pointer_check,pointer_dummy : pointer;
label bp_found,bp_not_found;
begin
 pc := @Check_Credentials;
 pd := @dummy;
 asm
     cld
     mov edx,pointer_check
     mov ecx,pointer_dummy
     mov al,$CC
     repne scasb
     jz bp_found
     jmp bp_not_found
 end;
 bp_found :
 application.terminate;
 bp_not_found:
 Check_Credentials(EdtUser.text,EdtPass.text);
end;

 

Ding

 

Posted (edited)

Hi

it's because of your assembly code !

read about used instruction here(repne scasb) :

https://c9x.me/x86/html/file_module_x86_id_287.html

 

Fixed code :

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  pointer_check, pointer_dummy: pointer;

label bp_found, bp_not_found;
begin
  pointer_check := @check_credentials;
  pointer_dummy := @Dummy;
  asm
    cld
    mov edi,pointer_check
    mov ecx,pointer_dummy
    sub ecx, pointer_check
    mov al,$CC
    repne scasb
    jz bp_found
    jmp bp_not_found
  end;
bp_found:
  application.terminate;
  exit; //you will findout why you should use this
bp_not_found:
  check_credentials('user', 'pass');
end;

 

 

BR,

h4sh3m

Edited by h4sh3m
  • Like 1
  • Thanks 2
Posted
1 hour ago, h4sh3m said:

Hi

it's because of your assembly code !

read about used instruction here(repne scasb) :

https://c9x.me/x86/html/file_module_x86_id_287.html

BR,

h4sh3m

You're right brother , I didn't pay attention to what was written in the book , the asm code receives two pointers , wheras I had to pass a pointer followed by the length of the function in bytes . 

(Exit) ensure that (check_credentials) will never get executed  .

Problem solved , thanks everyone for helping me , I really appreciate that  😇

 

 

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...