ding Posted May 4, 2020 Posted May 4, 2020 (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 : 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 May 4, 2020 by ding
ding Posted May 4, 2020 Author Posted May 4, 2020 (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 May 4, 2020 by ding
deepzero Posted May 5, 2020 Posted May 5, 2020 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. 1
ding Posted May 5, 2020 Author Posted May 5, 2020 (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 May 5, 2020 by ding
deepzero Posted May 5, 2020 Posted May 5, 2020 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. 1
h4sh3m Posted May 5, 2020 Posted May 5, 2020 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 2
ding Posted May 5, 2020 Author Posted May 5, 2020 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
h4sh3m Posted May 6, 2020 Posted May 6, 2020 (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 May 6, 2020 by h4sh3m 1 2
ding Posted May 6, 2020 Author Posted May 6, 2020 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 😇
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now