Exetools  

Go Back   Exetools > General > General Discussion

Notices

Reply
 
Thread Tools Display Modes
  #1  
Old 05-08-2005, 11:15
nikola nikola is offline
Friend
 
Join Date: Jan 2004
Location: Your head
Posts: 115
Rept. Given: 0
Rept. Rcvd 0 Times in 0 Posts
Thanks Given: 0
Thanks Rcvd at 1 Time in 1 Post
nikola Reputation: 0
Question Writing small debugger

I'm trying to write a small "debugger" for one specific app. For starters i want to get to EP but i dont know how to do that. Here is how i tried to do so, but when i sompare used memory of app how Olly loaded and how i loaded it, Ollys child process has occupied more memory.

Code:
  if DWORD(CreateProcess('1.exe',nil,nil,nil,FALSE,DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS,nil,nil,si,pi)) = 0 then begin
    ShowLastError();
    ExitProcess(0);
  end;
  WaitForDebugEvent(dbevent, INFINITE);
  ContinueDebugEvent(pi.dwProcessId , pi.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
  if dbevent.dwDebugEventCode <> CREATE_PROCESS_DEBUG_EVENT then begin
    MessageBox(0, 'Couldnt get to EP !', 'Error !!!', MB_ICONERROR);
    Exit;
  end;
  if dbevent.dwDebugEventCode = CREATE_PROCESS_DEBUG_EVENT then MessageBox(0, 'Got to EP !', 'OK !!!', MB_ICONERROR);

  stop := False;
  while not stop do begin
    stop := True;
    if dbevent.dwDebugEventCode = LOAD_DLL_DEBUG_EVENT then Stop := False;
    if dbevent.dwDebugEventCode = CREATE_THREAD_DEBUG_EVENT then Stop := False;
    if dbevent.dwDebugEventCode = CREATE_PROCESS_DEBUG_EVENT then Stop := False;

    WaitForDebugEvent(dbevent, INFINITE);
 		dwStat := DBG_EXCEPTION_NOT_HANDLED;
    case dbevent.dwDebugEventCode of
      EXCEPTION_DEBUG_EVENT:  begin
                                case dbevent.Exception.ExceptionRecord.ExceptionCode of
                                  EXCEPTION_BREAKPOINT: dwStat := DBG_CONTINUE;
                                end;
                              end;
      EXIT_PROCESS_DEBUG_EVENT: begin
                                  MessageBoxA(0, 'Prog exited :/', 'Error', MB_ICONERROR);
                                  CloseHandle(hFile);
                                  ExitProcess(0);
                                end;
    end;
		ContinueDebugEvent(dbevent.dwProcessId,dbevent.dwThreadId,dwStat);
  end;
I've also tried to write $CC to EP and run until debug exception, but it doesnt break ir just runs. Like i wrote int3 to wrong process. But i didnt miss the handles for sure...
Reply With Quote
  #2  
Old 05-08-2005, 15:46
omidgl omidgl is offline
Friend
 
Join Date: Jul 2004
Posts: 86
Rept. Given: 10
Rept. Rcvd 4 Times in 3 Posts
Thanks Given: 0
Thanks Rcvd at 5 Times in 5 Posts
omidgl Reputation: 4
I've read this tut from ICZlion. He made a simple debugger like what you need as an example. The codes are in MASM32 but it will guide you with Win32 Debug APIs as sure.

http://win32assembly.online.fr/tut28.html
http://win32assembly.online.fr/tut29.html
http://win32assembly.online.fr/tut30.html

Regards
O M I D
Reply With Quote
  #3  
Old 05-08-2005, 16:30
xixiaolou
 
Posts: n/a
A man named "Nico Bendlin" who had translate iczlion's masm code to delphi code. You can search for get it.
Reply With Quote
  #4  
Old 05-08-2005, 20:44
Lunar_Dust
 
Posts: n/a
That is the ugliest piece of code I've ever seen. First off, you don't want to return EXCEPTION_NOT_HANDLED right away. That first exception is the built in system breakpoint, and you have to return DBG_CONTINUE to it.

Secondly, any patching of EP's has to be done during that initial system breakpoint (all debuggers get an auto breakpoint (int 3) by the system, at EP, to let them set up).

Here is C++ code that does things the correct way.

Code:
// We only do anything if the user selected a file.
	if (GetOpenFileName(&ofn)==TRUE) 
	{

	//MessageBox(DialogHwnd,g_FullFileName,"info",MB_OK);

    // Start the child process. 
    if( !CreateProcess(g_FileName, //  (use command line). 
        NULL, // Command line - we pass the DLL / OCX name on command line to loader
        NULL,             // Process handle not inheritable. 
        NULL,             // Thread handle not inheritable. 
        FALSE,            // Set handle inheritance to FALSE. 
        DEBUG_ONLY_THIS_PROCESS | CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, //creation flags. 
        NULL,             // Use parent's environment block. 
        NULL,             // Use parent's starting directory. 
        &si,              // Pointer to STARTUPINFO structure.
        &pi )             // Pointer to PROCESS_INFORMATION structure.
    ) 
    {
        //printf( "CreateProcess failed ! GetLastError returns %d \n",GetLastError() );
	

		goto Done;
    }



   // Wait until child process exits.
    for(;;) 
	{ 
 
	// Wait for a debugging event to occur. The second parameter indicates 
	// that the function does not return until a debugging event occurs. 
 
	WaitForDebugEvent(&DebugEv, INFINITE); 
 
	// Process the debugging event code. 
		
		dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;

		ZeroMemory(&CurrentContext,sizeof(CurrentContext));

		switch (DebugEv.dwDebugEventCode) 
		{ 
			case EXCEPTION_DEBUG_EVENT: 
			// Process the exception code. When handling 
			// exceptions, remember to set the continuation 
			// status parameter (dwContinueStatus). This value 
			// is used by the ContinueDebugEvent function. 
				
				switch (DebugEv.u.Exception.ExceptionRecord.ExceptionCode) 
				{	
				

					// This breakpoint is called once always.
					case EXCEPTION_BREAKPOINT: 
					// First chance: Display the current 
					// instruction and register values. 
						
					
						if (DoneOnce == FALSE)
						{
							// First time thru, breakpoint is from windows system

							
							// Call Breakpoint initialize routines from here
							
							dwContinueStatus = DBG_CONTINUE;
							DoneOnce = TRUE;

							// Remember to get out here ! 
							break;

						}
						
						
						if (DoneOnce == TRUE)
						{
						
							// pass unexpected int3 exception back to program
							
							dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
							
							break;
						
						}
								
							
					case EXCEPTION_SINGLE_STEP:
						// might have to handle my own single stepping routine here,
						// so I can preserve breakpoints...

						//printf("Single step at %Xh \n",DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
						
							
						// this is a single step that wasn't from us
						dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
						

					
						break;



					case EXCEPTION_PRIV_INSTRUCTION:

						//	printf("Privileged instruction encountered \n");
						// Looks like this exception is not ours..
						
						  dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
						
						break;

					// PASS ALL OTHER TO PROGRAM AS WELL
					default:
					// Handle other exceptions. 
						
						//printf("Unknown exception at %Xh \n",DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
						dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
						
						break;
				} 
 
			

				break;
			
			case CREATE_PROCESS_DEBUG_EVENT: 
			
				
				dwContinueStatus = DBG_CONTINUE;
				break;
 
		
			case EXIT_PROCESS_DEBUG_EVENT: 
				//printf("Process exiting..\n");
				dwContinueStatus = DBG_CONTINUE;
				goto Done;
				break;
  
		
			case CREATE_THREAD_DEBUG_EVENT:
				
				//printf("Creating a new thread..\n");
				
				dwContinueStatus = DBG_CONTINUE;
				break;

			case EXIT_THREAD_DEBUG_EVENT:
				//printf("Exiting a thread..\n");
				
				dwContinueStatus = DBG_CONTINUE;
				break;

			
			case LOAD_DLL_DEBUG_EVENT:
				//printf ("DLL being loaded..\n");
			
				
				dwContinueStatus = DBG_CONTINUE;
				break;
			
			case UNLOAD_DLL_DEBUG_EVENT:
				// We won't worry about this right now...
				// in the future, I might want to, depending on the target
				dwContinueStatus = DBG_CONTINUE;
				break;
				

			case OUTPUT_DEBUG_STRING_EVENT:
				
				dwContinueStatus = DBG_CONTINUE;
				break;

			
			default:
				dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
				break;

			
	
	
		} 

	

	// Resume executing the thread that reported the debugging event. 
 
	ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, dwContinueStatus); 
 
	} // end of FOR loop (infinite)


Done:

	//printf("Press a key to exit \n");

Also, you have to remember that if you ever use GetThreadContext or SetThreadContext calls in your debugger, DO NOT USE the stored hThread from the creation of the process. You have to get which thread is actually being run. Which means every time a DEBUG_CREATE_THREAD occurs, you need to have a list (I used a vector) to keep track of each new thread handle, so you can support multiple threads.

Of course I know you are trying to just make a simple debugger for now though.



-Lunar

Last edited by Lunar_Dust; 05-08-2005 at 20:47.
Reply With Quote
  #5  
Old 05-08-2005, 20:46
nikola nikola is offline
Friend
 
Join Date: Jan 2004
Location: Your head
Posts: 115
Rept. Given: 0
Rept. Rcvd 0 Times in 0 Posts
Thanks Given: 0
Thanks Rcvd at 1 Time in 1 Post
nikola Reputation: 0
Thanks for the info. Maybe trapflag will be usefull for getting to OEP.
Reply With Quote
  #6  
Old 05-08-2005, 20:50
Lunar_Dust
 
Posts: n/a
Well inside the first int3 handler you can put a 0xCC (int3) on your OEP, but usually since it's packed of course it won't work right. In that case you can either single step (might take a while) or you can use BPM's to break on access. Like I said, for either of these you will need to do a GetThreadContext/SetThreadContext pair, and for apps that might be multithreaded, you have to make sure you kept track of thread creation so you set the context of the correct thread. (See above post near bottom)

It does add complexity unfortunately, but it's the only way to make the debugger more robust and reliable on real applications.

Examples:

setting the single step flag in a thread
Code:
	
      // setting the single step flag
       CurrentContext.EFlags = CurrentContext.EFlags | 0x0100;
	SetThreadContext(hCurrentThread,&CurrentContext);
making a place to store thread handles as they are created
Code:
#include <map>
// global Threadmap list.
map<DWORD,HANDLE> ThreadMap;

storing thread handles when they are created
we do this since a debug event only gives us ThreadID's. It's a pain to get hThread from ThreadID, but we can track it ourselves with an "array" (map)
Code:
	case CREATE_THREAD_DEBUG_EVENT:
				
				//printf("Creating a new thread..\n");
				ThreadMap[DebugEv.dwThreadId] = DebugEv.u.CreateThread.hThread;
				dwContinueStatus = DBG_CONTINUE;
				break;
remember to remove a thread when its done
Code:
	case EXIT_THREAD_DEBUG_EVENT:
				//printf("Exiting a thread..\n");
				ThreadMap.erase(ThreadMap.find(DebugEv.dwThreadId));
				dwContinueStatus = DBG_CONTINUE;
				break;

getting the current thread when a debug exception occurs
Code:
	WaitForDebugEvent(&DebugEv, INFINITE); 
 
	// Process the debugging event code. 
		
		dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;

		ZeroMemory(&CurrentContext,sizeof(CurrentContext));

		hCurrentThread = ThreadMap[DebugEv.dwThreadId];

		switch (DebugEv.dwDebugEventCode) 
		{ 
			case EXCEPTION_DEBUG_EVENT: 
			// Process the exception code. When handling 
			// exceptions, remember to set the c




-Lunar

Last edited by Lunar_Dust; 05-08-2005 at 20:58.
Reply With Quote
  #7  
Old 05-08-2005, 21:26
nikola nikola is offline
Friend
 
Join Date: Jan 2004
Location: Your head
Posts: 115
Rept. Given: 0
Rept. Rcvd 0 Times in 0 Posts
Thanks Given: 0
Thanks Rcvd at 1 Time in 1 Post
nikola Reputation: 0
ow, ow, i didnt even see your post when i wrote my reply. Well, i trust you its ugliest. I dont like it either. Partly becouse it is really ugly and partly becouse i'm not sure what i'm writing there. I didnt read anything other than Help files when writing that.
Well, some things you said here i read from Icz Tutorials and tried them myself. As for threads, i dont really need to update it (unless its changed O_o) becouse this specific program has only 1 thread while i need to debug it. Later i'll just detach.
Thanks alot for these snippets

Hvala komšija
Reply With Quote
  #8  
Old 05-08-2005, 21:32
nikola nikola is offline
Friend
 
Join Date: Jan 2004
Location: Your head
Posts: 115
Rept. Given: 0
Rept. Rcvd 0 Times in 0 Posts
Thanks Given: 0
Thanks Rcvd at 1 Time in 1 Post
nikola Reputation: 0
Oh, and i forgot. When does first BREAKPOINT occur? You said system sets one on EP and thats what i understood from Icz tutorials. I tried getting to EP that way, but seems that i'm in Kernel when i get first BP O_o EIP is 7fxxxxxx. I didnt do any debugging before that. Those are first lines when i try to get there. I thought this might be ret before going to EP and tried to trace with trapflag but its like i stand in same place. I dont move from that EIP. I'll fix it somehow...
Reply With Quote
  #9  
Old 05-08-2005, 21:41
Lunar_Dust
 
Posts: n/a
Yes, I believe that first breakpoint will end you up in the system, but now you can go and write that 0xCC to the EP of the program, and then do a DBG_CONTINUE. Now the second 0xCC that comes thru will be that one that you set.

-Lunar
Reply With Quote
  #10  
Old 05-09-2005, 01:15
nikola nikola is offline
Friend
 
Join Date: Jan 2004
Location: Your head
Posts: 115
Rept. Given: 0
Rept. Rcvd 0 Times in 0 Posts
Thanks Given: 0
Thanks Rcvd at 1 Time in 1 Post
nikola Reputation: 0
Oh. Cool. I'll try it out now. I thought getting to OEP would be least problem. I had problems with VirtualProtect too but solved it...
Reply With Quote
  #11  
Old 05-09-2005, 09:11
goggles99 goggles99 is offline
Friend
 
Join Date: Aug 2004
Posts: 62
Rept. Given: 5
Rept. Rcvd 0 Times in 0 Posts
Thanks Given: 1
Thanks Rcvd at 4 Times in 4 Posts
goggles99 Reputation: 0
Post

Here is an example program with MASM source that should make thing quite a bit easier after looking over.

Un-FSG 2.0
http://giaubertin.free.fr/pages/Coding/cod_tool.html

from redirector
http://www.rif.fr.fm/

Good luck
Reply With Quote
  #12  
Old 05-09-2005, 18:55
nikola nikola is offline
Friend
 
Join Date: Jan 2004
Location: Your head
Posts: 115
Rept. Given: 0
Rept. Rcvd 0 Times in 0 Posts
Thanks Given: 0
Thanks Rcvd at 1 Time in 1 Post
nikola Reputation: 0
Well i finished mine before yousent me this like but i found other things to look at there Not to learn how to rebuild imports...
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Need help about IDA plugin writing softworm General Discussion 1 01-09-2006 08:55
writing my own OS.....where to start from?? loman General Discussion 33 06-29-2004 18:09


All times are GMT +8. The time now is 22:20.


Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX, chessgod101
( 1998 - 2024 )