OpenProcess
This function requires a Process ID as a parameter and returns a process handle. Process Handle is then handed over to a function like ReadProcessMemory or VirtualQueryex. And you know that Toolhelp32 has the ability to give you the process ID of any process. Therefore, if you can combine these two powers, you can be big. The strange thing is that Windows 95 allows you to open a process handle but not allow you to open a Thread Handle. Perhaps Microsoft believes that once the thread will make great destruction, it cannot be borne.
OpenProcess first converts the Process ID into a process_database pointer. The conversion process ID is exactly the same as the algorithm of the Process Database pointer and the conversion Thread ID is exactly the same. The first parameter converted pointer will be checked. Finally, OpenProcess calls an internal function, assigns a piece of space in the Handle Table of the current process and stores the Process_Database pointer into it.
OpenPROCESS virtual code:
// Parameters:
// DWORD FDWACCESS;
// bool finherit;
// dword idprocess;
// locals:
// rpocess_database ppdb;
// DWORD flags;
X_logsomekernelFunction (Function Number for OpenProcess);
// Convert the process id to a process_database
PPDB = PIDTOPDB (IdProcess);
IF (! ppdb)
Return 0;
IF (ppdb-> type! = k32obj_process) // make Sure Thread ID NOT Passed.
{
INTERNALSETLASTERROR (ERROR_INVALID_PARER);
Return 0;
}
Flags = fdaccess & 0x001fffbf; // Turn Off All Non-Allowed Flags.
// Flags like process_query_information
// and process_vm_write is allowed.
IF (Finherit)
Flags | = 0x80000000;
Flags | = process_dup_handle; // always pass. process_dup_handle
// allocate a new slot in the handle table of the current process.
// The slot contains the ppdb Pointer.
Return X_OpenHandle (PpCurrentProcess, PPDB, Flags);
SetFileaPistooem
This function changes the way the Kernel32 function related to the file name for the explanation of the file name. By default, kernel32 uses an ANSI string as a file name. If you call SetFileApistooem, you can use the OEM string. Please refer to the getModuleFileName and getModuleHandle two functions mentioned earlier.
The internal implementation of this function is not simple. He intercepted a pointer to the current Process Database and set the FFileApisareoem flag.
ENVIRONMENT DATABASE
The 40H member of Process Database is a pointer, pointing to an important data structure, with data related to the process. Inside the Kernel32, this pointer is PEDB, I explained it as "Pointer to Environment Database". It is like treating Process_Database. I describe the structural layout of Environment Database in ProCDB.H, as shown below: TypeDef struct _Environment_Database
{
PSTR pszenvironment; // 00h Pointer to Environment; PSZZENVIRONMENT
DWORD UN1; // 04H
PSTR pszcmdline; // 08h Pointer to Command Line
PSTR pszcurdirectory; // 0ch Pointer to current Directory
LPStartupinfoa Pstartupinfo; // 10h Pointer to Startupinfoa Struct
Handle hstdin; // 14h standard Input
Handle hstdout; // 18h Standard OUTPUT
Handle hstderr; // 1ch standard Error
DWORD UN2; // 20h
DWORD inheritconsole; // 24h
DWORD BREAKTYPE; / / 28H
DWORD BREAKSEM; / / 2CH
DWORD BREAKEVENT; // 30h
DWORD BREAKTHREADID; // 34H
DWORD BREAKHANDLERS; // 38H
} Environment_Database, * penvironment_database;
Now let's take a look at the specific meaning of these members:
00h pstr pszenvironment
This location points to the environmental area of the process. The so-called environmental zone is a standard DOS environment (forms such as string = value; string = value). The process environment block is a memory, located in each process private address space, usually above the address of the module being loaded.
04H DWORD UN1
This location meaning is unclear. It is usually always 0.
08H PSTR PSZCMDLINE
This member contains the command line parameters in the CREATEPROCESS function. In most cases this command line is a complete EXE file name. Sometimes it will point to empty strings (0).
0CH PSTR PSZCurrdirectory
This member points to the current disk directory
10h lpstartupinfoa pstartupinfo
This is a pointer, pointing to the StarupInfoA structure (defined in WinBase.h). The StartupInfoA structure is one of the parameters of CreateProcess, which can be used to specify the size, title, and standard File Handles, etc. of the window. This member refers to a copy of this structure.
14h Handle Hstdin
This is a File Handle that uses it as a standard input device. This value is -1 if not found (for example, a GUI program).
18h Handle Hstdout
This is a File Handle that uses it as a standard output device. If you don't find (eg, a GUI program), this value is -1.1ch handle hstderr
This is a File Handle that uses it as a standard error output device. This value is -1 if not found (for example, a GUI program).
20h DWORD UN2
This member is meaningless. Usually 1.
24h DWORD Inheritconsole It can be speculated from the name that this member represents whether the process inherits from the Console program. Please refer to the create_new_console flag of the CreateProcess function. In my observation, the value of this member is always 0.
28h DWORD BREAKTYPE
This member is most likely to indicate how Console Event is handled. In the program I have implemented, it usually is 0, occasionally 0xA.
2Ch DWORD BREAKSEM
Usually 0, but if the program calls setconsolectrlHandle, this member will point to a kernel32 semaphore object (k32obj_semaphone).
30h dword breakevent
Usually 0, but if the program is called setConsolectrlHandle, this member will point to a kernel32 Event Object (k32obj_event).
34H DWORD BREAKTHREADID
Usually 0, but if the program is called setConsolectrlHandle, this member will point to a thread object (K32Obj_thread), and the thread is the thread itself installed this processing routine.
38H DWORD BREAKHANDLES
Usually 0, but if the program calls setConsolectrlHandle, this member will point to a data structure allocated from the Kernel32 Shared HEAP, and store a series of installed main control functions (Console Control Handler).
Let us now look at the virtual code of these functions. This time is related to Evnironment_DataBas.
Getcommandlinea
In fact, this function is not too much. It returns the command line pointer, and the command line string is stored in Environment Database.
Getcommandlinea's virtual code:
Return PpCurrentProcess-> PEDB.PSZCMDLINE;
GetEnvironmentStrings
This function returns a pointer associated with Environment Database. It is worth noting that there are two differences between the true code of this function and the SDK documentation.
The SDK file said:
When GetEnvironmentStrings is called, it assigns a memory as a environmental area. When this environment zone is no longer needed, it should call freeENvironmentstrings.
This is true for Windows NT. But it is incorrect to Windows 95.
FreeEnvironmentStringa
This function is more interesting. Since GetenvironemntStinga in Windows 95 does not really allocate memory, there is no matter what freeenvironmentstirnga must work. However, it may be purely for pastime, this function checks its string parameters to see if it matches the environmental area pointer in Environment Database. If you don't match, FreeENVIRONMENTSTRINGA is set to ERROR_INVALID_PARAMTER. Getstdhandle
This function is directly like you can imagine. This function gives it a device (stdin, stdou, stderr et al.) Will return the corresponding File Handle. If you give a counterfeit DeviceID, this function will fail and set the lasterror code.
GetStdHandle function virtual code:
// Parameters:
// dword fdwdevice
// locals:
// Penvironment_Database PEDB
PEDB = PPCurrentProcess-> PEDB;
IF (fdwdevice == std_input_handle)
Return PEDB-> HSTDIN;
ELSE IF (fdwdevice == std_output_handle)
Return PEDB-> HSTDOUT;
ELSE IF (fdwdevice == std_error_handle)
Retrun Pedb-> HSTDERR;
INTERNALSETLASTERROR (ERROR_INVALID_FUNCTION);
Return 0xfffffff;
SetStdHandle
This function is more interesting than getstdhandle. It first verifies that Handle does represent a legitimate Kernel32 object. How to do it? Please x_converthandletok32Object handle. The latter will return a pointer, pointing to the corresponding kernel32 object - if the handle is legal. SetStdHandle never uses the K32 object pointer, a simple NULL test is the only action that needs to do. After testing the legitimacy of the HHANDLE parameter, the remaining function code puts the HHANDE to the appropriate position of the Environment Database structure.
Process Handle Tables
The 44h offset of Process_Database is a pointer, pointing to the process of Handle Table. I will use the word representative from Handle Table. In addition to File Handle, Windows 95 also produces Handle of other system objects, such as process objects, threads, events, mutex, and more.
The content of Handle is in theory that it is opaque, that is, Handle itself has no way to tell you what it is representative. If it is 5, you judge that this is a File Handle or a Mutex Handle. However, one but you know the Handle Table of the Windows 95 process, you can easily generate a Handle value with the data it referenced.
The Handle Table structure of the Windows 95 process is very simple. The first DWORD is placed in the maximum capacity of this table (number of items). This initial value is 0x30 (48). However, this does not mean that the process can only have 48 open hands. When the process requires more Handles, kernel32 will reassign a memory so that the form has a growth space. Add 0x10 (16) Handles each time. There seems to have no significant upper limit. I wrote a small program, constantly opening File Handles, still good -255 is DOS after more than 255 Handles. After the first DWORD, it is an array composed of many structures. Each structure consists of two DWORD:
DWORD FLAGS
DWORD PK32OBJECT
The second DWORD is a pointer, pointing to 17 possible K32 objects. As for the first DWORD, it is the Access Control Flags of this object. The meaning of these markers is related to the object. For a k32obj_process object, these flags will be process_xxx (defined in Winnt.h), like process_termnate, process_vm_read, and more.
By here, maybe you can feel what is Handle. If you guess your handle is an index, point to the Handle Table of the process, you are right! One but thinking, you can easily put a Handle value to the Kernel32 object type it referenced. A useless handle, two DWORDs must be filled with 0. When the program assigns a new Handle, Kernel32 uses the index of the first blank term in the handle table as a handle. But the Handle Table of the browsing process is not a Microsoft's proposal action.
to add on:
The following is from "Windows Core Programming" Chapter 3
When a process is initialized, the system assigns a handle table for it. This handle is only used for K32 objects (ie, kernel objects), which is not used for user objects or GDI objects. The detailed structure and management method of the handle is not described. But as a qualified Windows programmer, you must know how to manage the handle of the process. Since this information has no documentation, it cannot guarantee that all details are correct. The figure below shows the appearance of the handle of the process. It can be seen that it is just an array of data structures, each structure contains a pointer to K32 objects (ie, kernel objects), an access shield and some flags.
When the process is initialized, its handle table is empty. Then, when the thread in the process invokes a function of creating a K32 object, such as CREATEFILEMAPPING, KERNEL32 assigns a piece of memory for the object and initializes. These, Kernel32 scans the handle of the process to find an empty item. Initializing its pointer member to the memory address of the K32 object, the access shield is set to all access rights, and each flag is also set accordingly.
Some functions that are used to create K32 objects (ie, kernel objects) are listed (not a full list):
l CreateThread
l createfile
l createfilemapping
l CreateSemaphore
l createevent
l createmutex
These functions that create the K32 object returns a handle associated with the calling process, which can be used in any thread running in the same process. This handle value is actually the index in the handle of the process, which is used to identify the storage location of the K32 object. Therefore, when the strip is an application and observes the actual value of the K32 object handle, some smaller values are seen, such as 1, 2, etc. Remember, the meaning of the handle does not log in documentation and may change at any time. In fact, in Windows 2000, the returned value is used to identify the number of bytes of the object of the handle of the process, not the index number itself. Again again, since the handle value is actually the index in the process handle table, these handles are related to the process and cannot be used by other processes.
If you can't create a K32 object, the returned handle value is usually 0 (NULL). This happens because the system's memory is very short, or problems with security. However, there is a few function returned when it fails at runtime is -1 (Invalid_Handle_Value). For example, if the CreateFile does not open the specified file, it will return to INVALID_HANDLE_VALUE instead of NULL. Be careful when the return value of the function of creating a K32 object is checked. It is important to note that the return value can be compared to InvaliD_Handle_Value only when the CreateFile function is called. The following code is incorrect:
Handle hmutex = creteMutex (....);
IF (hmutex == invalid_handle_value)
{
// We will Never Execute This Code Because CreateMutex Returns Null IF IT Fails.
}
When you turn off the K32 object, you need to call the CloseHandle function. This function first checks the handle table of the calling process to ensure that the index (handle) passed to it is used to identify the object that the process has access to access. If the system can get the pointer of the K32 object, it can determine if the reference count of the object is 0, if yes, the K32 object will be destroyed by Kernel 32 while recovering the memory it takes up.
If you pass an invalid handle value to CloseHandle, there will be two cases: If the process runs properly, CloseHandle returns false, and GetLastError returns ERROR_INVALID_HANDLE. If the process is in debug, the system will notify the debug program for unlock.
Before CloseHandle returns, it will clear the project's project, which is now invalid to your process, should not try again. Regardless of whether the K32 object has been revoked, the operation of the clerical handle table will occur. After the CLOSEHANDLE Han book is called, the access to the K32 object will no longer have access to the K32 object. However, if the reference count of the object is not decremented to 0, then the K32 object will still exist.
If you forget to call the CloseHandle function, do you have a memory leak? The answer is possible, but not necessarily. When the process is running, the process may leak resources (such as K32 object). However, when the process ends, the operating system ensures that any resources used by the process are released, which is guaranteed. For K32 objects, the system will perform the following: When the process is terminated, the system will automatically scan the handle table of the process. If you have any objects that have no closed before the termination process run, the system will turn off the handle of these objects. If the reference count of these K32 objects will be 0, the K32 object will be reclaimed by the system. It is necessary to remember that the lifecycle of the K32 object is at least as long as the object it represents, and sometimes it is much longer than its representative. For example, the process k32 object, when a process ends, the reference count of its corresponding K32 object will be decremented by 1, and if there are other processes in this K32 object, it will not be destroyed.
Some functions of the handle of handle:
l GetHandleinFormation
l setHandleinformation
l CloseHandle
l DuplicateHandle
Thread (thread)
You have also read the modules and processes, as long as you want to see the thread, you can complete the entire Kernel32 infrastructure journey. The process is mainly to express the ownership of File Handles, address space, etc., and threads primarily express the facts of code execution in the module. You see, there are so many things to associate with each other, I am hard to smoke something from another thing. For example, when discussing the process, I must first mention threads and synchronous control objects.
From the abstract level, the thread is a convenient expression that allows you to perform a part of the code - when the code is waiting for some external events. After further assigning the work of the process to the thread, you seem to eliminate actions like "pooling loop". Pooling loop Wasted many CPU time.
At any time, the thread may be one of three states. The first is: execution in a state. At this time, the content of the CPU register is the value of the register of the thread.
The second is: Read to Run State. There is no reason for thread in this state that it will not be executed - just a morning and evening problem. It is finally possible to control the CPU.
The third is: block block. The thread is blocked, indicating that it is waiting for something. Before that, the CPU scheduler did not arrange the thread. It is called the synchronization control object (Synchronization Objects) that causes thread blocking in the execution. The Synchronous Control of Windows has: Critical Sections, Event, Semaphores, Mutexes.
With regard to the basic functions and use of synchronous objects, refer to Jeffrey Richter's "Advanced Windows 3rd" or "Windows Core Programming", and a book "Win32 multi-threaded program design" is also very good. This book is set you know the existence of synchronous control objects and know how to use them.
Initially, each process begins with a main thread. If you need, the process can generate more threads, so that the CPU can perform code of different sections in the process at the same time (in multiple CPU environments, real concurrent execution can be realized, in single CPU environment, actually at the same time There is only one thread in execution). The standard example is a text processing software. When the text processing software needs to be printed, it handles the print job to another thread, so that the main thread can still respond to the user's actions. Of course, if you are familiar with the CPU's infrastructure, you will know that for only one CPU machine, it is impossible to perform two threads simultaneously. "Many threads perform" illusion is implemented by VMM (Virtual Memory Manage Virtual Memory Management). It uses a hardware timer and a set of complex rules, fast switching between different threads (common CPU scheduling mode: Time slice rotation algorithm, multi-level feedback queue scale algorithm, detailed reference to explain the principle of operating system principles ).
Microsoft declares that the TimeSlice of Windows 95 is 20 milliseconds (MilliseConts). That is, if other factors (such as thread priority) are not considered, each thread performs 20 milliseconds, and then switches to other threads. I will be more detailed in the [Thread Priority Thread Priority] section. However, I have to declare that this book does not intend to discuss thread schedule and VMM thread scheduler. Just like synchronous control objects, these topics should be discussed another book.
Like the process, the thread is a memory that is allocated from the kernel32 shared memory. This memory saves the necessary data, so that kernel32 is used to maintain a thread. Although I said "All necessary data", there are actually some pointers in this memory point to other structures, but you know what I mean. There is a book called Thread Database or TDB in this book (note that in different times, Microsoft uses TDB represents TASK DATABASE and Thread Database.). Just like Process Database, Thread Database is also a K32 object, its first DWORD value is 6, indicating that this is a k32obj_thread object.
If you are a senior programmer, you can rewrite DDK or use WDEB386 or Softice / W, you may have encountered another data structure related to threads, named THCB (Thread Control Block). THCB is the form of a thread in RING0. In Windows 95, threads behave as RING0 and RING3 two data structures. Ring0 level code such as VMM VXD, WDM (Windows 2000 or Later) processes threads via THCB. The RING3 code is like Kernel32 to handle threads through Thread Database. This chapter describes the behavior and mechanism of RING3 threads and does not intend to cover Ring0 level.
supplement:
If Microsoft's Windows NT / 2000 is an operating system of a microelectronics, it is not recognized that there are two different but related control mechanisms in the system core (RING0) and user-level (RING3), for example, in OS materials In the case of the PCB (Process Control Block), this book considers Process Database to represent a process, which is used in this book to explain the explanation of Thread Database and Thread Control Block, whether it can be considered to be a process in Ring3. And the PCB is the process of the process in RING0? What is the true meaning of the operating system? Is there a corresponding relationship between these two? For software like Softice, you will definitely be deal with these structures of RING0, and study it carefully. These will be greatly helpful to knowing We know Windows.
The thread itself has something. The first thing is a set of registers (Register Set). As I said earlier, the thread is either executed, or it is to be executed (this is not nonsense? Hehe). When the thread is being executed, its register set will be placed in the CPU register, that is, the EIP value of the thread is the value of the CPU register EIP. When the thread is not executed, its register must be stored somewhere in memory. Therefore, each thread has a pointer to a memory block, where the register content is stored there.
Another thing that has a relationship with each thread is a process. Everything in the process shared everything in the process. For example, the process has Memory Context and a private address space, so all threads are running in the same address space. The process has a Handle Table, used to manage files, console, memory mapped files, events, etc., all threads in the process also share these Handles. If Hande 3 represents a memory mapping file, any thread in the process can use Handle 3 to use this memory map file.
Threads also have many other things. Each thread has a dedicated stack, a dedicated message queue, a dedicated Thread Local Storage (TLS), and a dedicated structured exception handling chain (if you don't know what is the next two, don't worry, later I will introduce them). In addition, threads may request, release the ownership of synchronous control objects during execution. After I have seen Thread Database, I will explain these things.
What is Thread Handle? What is Thread ID?
This chapter I have said the difference between the Process Handle and Process IDs earlier. My instructions can be easily sleeve to Thread Handle and Thread ID - just change the process to threads. If you are not sure, please look back to see what is Process Handle? What is the Process ID? That section.
GetThreadHandle returns a constant (Microsoft always said that it is a "virtual handle") that can be applied to any real thread handle can be used:
GetThreadHandle function's virtual code:
X_logsomekernelFunction (Function Number for getCurrentThread);
Return 0xffffffe;
Just like getCurrentProcessid, getCurrentThreadId returns a pointer, pointing to the current Thread Database (but the kernel32 team will add a confusing value): The virtual code of the getCurrentThreadID function:
Return Tdbtotid (PPCurrentThread);
Why is Kernel 32 confused? let us see:
Virtual code for tdbtotid functions:
// Parameters:
// thread_database * PTDB
IF (obsfucatordword == false)
{
_Debugout ("TDBTOTID () Called Too Early! ObsfuCator Not Yet Initialized!");
Return 0;
}
IF (PTDB & 1)
{
_Debugout ("TDBTOTID: THIS TDB LOOKS LIKE A TID (0% 1X) DO"
"Statck Trace Before Reporting As Bug.");
}
// Here's the key! Xor the obsfucator dword with the thread database
// Pointer to make the tid value.
Return PTDB ^ obsfucatordword;
If you think this is a pdbtopid function that seems to be preceding before, then you are right. Kernel32 converts the Process Database pointer and Thread Database pointer to IDS using the same ObsFucatorDword. Once you know the value of ObsFucatorDword (and remember Microsoft spelling this word), you can convert a process or a preliminary ID to a useful pointer. I have to say it again, this is not encouraged, but in order to learn more about the underlying action of the system, we don't have much choice. J