I. Introduction of development content
In order to debug a process, you must first connect the debugger and the process in some way. So, I
The debugger is either loading an executable program and running it, or it is dynamically attached to a running
The process. The Debugging Interface for Windows (Windows Debugging API) provides a very simple way to complete
These two points.
There are subtle differences between running a program and attaching to a program. The advantage of opening a program is that he can
Complete control program before you line any code. This is useful when analyzing viruses or malicious code. Attached to a
Process, just forced into an already running process inside, it allows you to skip the boot section of the code, analyze
The code you are interested in. The place you are analyzing is where the program is currently executing.
The first method, in fact, is to invoke the program from the debugger itself (the debugger is the parent process, the process of being debugged
Greater control privileges). Create a process on Windows with the CreateProcessA () function. To pass a particular flag
Into this function so that the target process can be debugged.
Goal: Open a process with CreateProcess
Second, the need to use the WINAPI function
CreateProcess
Function prototype: BOOL CreateProcess (lpctstr lpapplicationname,lptstr lpcommandline,lpsecurity_attributes lpprocessattributes,lpsecurity_attributes lpthreadattributes,bool binherithandles,dword Dwcreationflags,lpvoid lpenvironment,lpctstr lpcurrentdirectory,lpstartupinfo lpstartupinfo, lpprocess_informationlpprocessinformation); parameter: Lpapplicationname points to a null-terminated string that specifies the executable module. This string can be an absolute path to an executable module or a relative path, in which case the function uses the current drive and directory to establish the path to the executable module. This parameter can be set to NULL, in which case the name of the executable module must be at the front of the lpCommandLine parameter and separated by a space character from the following characters. lpCommandLine points to a null-terminated string that specifies the command line to execute. This parameter can be null, then the function uses the string specified by the Lpapplicationname parameter as the command line for the program to run. If both the Lpapplicationname and lpCommandLine parameters are not empty, then the Lpapplicationname parameter specifies the module to be run, and the lpCommandLine parameter specifies the command line of the module that will be run. The new running process can use the GetCommandLine function to get the entire command line. The C language program can use the ARGC and argv parameters. Lpprocessattributes points to a security_attributes struct, which determines whether the returned handle can be inherited by the quilt process. If the lpprocessattributes parameter is empty (null), then the handle cannot be inherited. In Windows NT: The Lpsecuritydescriptor member of the security_attributes struct specifies the security descriptor for the new process, and if the argument is null, the new process uses the default security descriptor. LpthreadattrIbutes with Lpprocessattribute, but this parameter determines whether the thread is inherited. Usually set to Null.binherithandles indicates whether the new process inherits the handle from the calling process. If the value of the parameter is true, each inheritable open handle in the calling process inherits the quilt process. The inherited handle has exactly the same value and access rights as the original process. DWCREATIONFLAGS Specifies the additional flags that are used to control the creation of priority classes and processes. The following creation flags can be specified in any combination of methods except those listed below. ⑴ value: Create_default_error_mode meaning: The new process does not inherit the error mode of the calling process. The CreateProcess function assigns the current default error mode to the new process as an alternative. The application can call the SetErrorMode function to set the current default error mode. This flag is useful for multithreaded shells running in environments where there is no hardware error. For the CreateProcess function, the default behavior is to inherit the caller's error pattern for the new process. Set this flag to change the default processing mode. ⑵ value: Create_new_console meaning: The new process will use a new console instead of inheriting the parent process's console. This flag cannot be used with the detached_process flag. ⑶ value: Create_new_process_group meaning: The new process will be the root process of a process tree. All processes in the process tree are child processes of the root process. The user identifier for the new process tree is the same as the identifier for this process, which is returned by the lpprocessinformation parameter. The process tree often uses the Generateconsolectrlevent function to allow the sending of CTRL + C or Ctrl+break signals to a set of console processes. ⑷ value: CREATE_SEPARATE_WOW_VDM If set, the new process will run in a private virtual DOS machine (VDM). Also, by default, all 16-bit Windows applications run as threads in the same shared VDM. The advantage of running a 16-bit program alone is that an application crash will only end the operation of this VDM, and other programs running in different VDM will continue to run normally. Similarly, 16-bit Windows applications running in different VDM have different input queues, which means that if a program temporarily loses its response, the application in the standalone VDM can continue to get input. ⑸ Value: CREATE_SHARED_WOW_VDM if the DEFAULTSEPARATEVDM option of the Windows segment in Win.ini is set to true, the labelThe CreateProcess function crosses this option and runs a new process in a shared virtual DOS machine. ⑹ value: create_suspended meaning: The main thread of the new process is created in a paused state until the call ResumeThread function is called. ⑺ value: create_unicode_environment meaning: If set, the environment block specified by the Lpenvironment parameter uses UNICODE characters, and if empty, the environment block uses ANSI characters. ⑻ value: debug_process meaning: If this flag is set, the calling process will be treated as a debugger, and the new process will be treated as the process being debugged. The system notifies the debugger of all debug events that occur by the debugger. If you use this flag to create a process, only the calling process (the process that calls the CreateProcess function) can call the Waitfordebugevent function. ⑼ value: debug_only_this_process meaning: If this flag is not set and the calling process is being debugged, the new process becomes another debug object for debugging the debugger that invokes the process. If the calling process is not debugged, the behavior about debugging is not generated. ⑽ value: detached_process meaning: For the console process, the new process does not have access to the parent process console. The new process can create a new console by itself through the AllocConsole function. This flag cannot be used with the CREATE_NEW_CONSOLE flag. (11) value: Create_no_window meaning: The system does not create a Cui window for the new process, which can be used to create a Cui program without windows. The dwCreationFlags parameter is also used to control the priority class of the new process, which is used to prioritize the thread scheduling for this process. If the following priority class flags are not specified, then the default priority class is Normal_priority_class unless the process being created is idle_priority_class. In this scenario, the default priority class for the process is idle_priority_class. You can choose one of the following flags: Priority: High_priority_class Meaning: Indicates that the process will perform a time-critical task, so it must be run immediately to ensure that it is correct. This priority program takes precedence over normal priority or idle priority programs. An example is the Windows Task List, which gives the system load consideration in order to ensure that the user can respond immediately when the call is made. Be cautious when using high-priority because a high-priority CPU affiliate application can consume almost all of the CPU's available time. Priority: Idle_priority_cLass Meaning: The thread that indicates that the process runs only when the system is idle and can be interrupted by any high-priority task. For example, a screen saver. The idle priority is inherited by the quilt process. Priority: Normal_priority_class Meaning: Indicates that the process has no special task scheduling requirements. Priority: Realtime_priority_class Meaning: Indicates that the process has the highest priority available. A thread with a process with a real-time priority can interrupt the execution of all other process threads, including system processes that are performing important tasks. For example, a real-time process with a slightly longer execution time may result in insufficient disk cache or slow mouse reflection. Lpenvironment the environment block that points to a new process. If this parameter is empty, the new process uses the environment that invokes the process. An environment block exists in a block that consists of a null-terminated string, and this block is also null-terminated. Each string is in the form of a name=value. Because the equality flag is treated as a delimiter, it cannot be used as a variable name by an environment variable. Instead of using the environment block provided by the application, set this parameter directly to NULL, and the current directory information on the system drive is not automatically passed to the newly created process. For a discussion of this situation and how to deal with it, see the comments section. The environment block can contain Unicode or ANSI characters. If lpenvironment points to an environment block that contains UNICODE characters, the create_unicode_enⅵronment flag for the dwCreationFlags field is set. If the block contains ANSI characters, the flag is emptied. Note that an ANSI environment block is terminated by two 0 bytes: One is the end of the string and the other is used to end this fast. A Unicode environment block is terminated by four 0 bytes: Two represents the end of a string and two is used to end the block. Lpcurrentdirectory points to a null-terminated string that is used to specify the working path of the child process. This string must be an absolute path that contains the drive name. If this parameter is NULL, the new process will use the same drive and directory as the calling process. This option is a primary condition that requires the shell to launch applications and specify their drive and working directory. Lpstartupinfo points to a STARTUPINFO structure that determines how the main form of a new process is displayed. Lpprocessinformation points to a process_information structure that is used to receive identifying information for a new process.
third, the code
Create two Python files my_debugger.py and my_debugger_defines.py. We will create a parent class
Debugger () then gradually add a variety of debugging functions. In addition, put all the structures, unions, constants into
my_debugger_defines.py convenient for later maintenance.
# my_debugger_defines.py
From ctypes Import *
# Let's map the Microsoft types to ctypes for clarity
WORD = C_ushort
DWORD = C_ulong
Lpbyte = POINTER (c_ubyte)
LPTSTR = POINTER (C_char)
HANDLE = c_void_p
# Constants
Debug_process = 0x00000001
Create_new_console = 0x00000010
# Structures for CreateProcessA () function
Class Startupinfo (Structure):
_fields_ = [
("CB", DWORD),
("lpreserved", LPTSTR),
("LpDesktop", LPTSTR),
("Lptitle", LPTSTR),
("DwX", DWORD),
("DwY", DWORD),
("Dwxsize", DWORD),
("Dwysize", DWORD),
("Dwxcountchars", DWORD),
("Dwycountchars", DWORD),
("Dwfillattribute", DWORD),
("DwFlags", DWORD),
("Wshowwindow", WORD),
("CbReserved2", WORD),
("LpReserved2", Lpbyte),
("hStdInput", HANDLE),
("Hstdoutput", HANDLE),
("Hstderror", HANDLE),
]
Class Process_information (Structure):
_fields_ = [
("hprocess", HANDLE),
("Hthread", HANDLE),
("Dwprocessid", DWORD),
("dwThreadID", DWORD),
]
# my_debugger.py
From ctypes Import *
From my_debugger_defines Import *
KERNEL32 = Windll.kernel32
Class Debugger ():
def __init__ (self):
Pass
def load (Self,path_to_exe):
# Dwcreation flag determines how to create the process
# set creation_flags = Create_new_console if you want
# to see the calculator GUI
Creation_flags = debug_process
# Instantiate the structs
Startupinfo = Startupinfo ()
Process_information = Process_information ()
# The following and the started process
# to is shown as a separate window. This also illustrates
# How different settings in the Startupinfo struct can affect
# the debuggee.
Startupinfo.dwflags = 0x1
Startupinfo.wshowwindow = 0x0
# We then initialize the CB variable in the startupinfo struct
# which is just the size of the struct itself
STARTUPINFO.CB = sizeof (STARTUPINFO)
If Kernel32. CreateProcessA (Path_to_exe,
None,
None,
None,
None,
Creation_flags,
None,
None,
ByRef (Startupinfo),
ByRef (process_information)):
Print "[*] We have successfully launched the process!"
Print "[*] PID:%d"% process_information.dwprocessid
Else
Print "[*] error:0x%08x."% kernel32. GetLastError ()
#my_test. py
Import My_debugger
debugger = My_debugger.debugger ()
Debugger.load ("C:\\windows\\system32\\calc.exe")
Operation Result:
Connected to Pydev Debugger (build 145.844)
[*] We have successfully launched the process!
[*] pid:4720
Python Grey Hat study Note: Write a windos debugger (i)