Win2000 Process Virtual Memory Data Search and Modification

zhaozj2021-02-16  58

Windows2000 User Mode Memory Scan [Repost] Sprite

Brief description:

This paper briefly describes the basic theory and implementation of memory scanning under Windows2000. Memory scan is an important technology, there is a considerable range of applications: such as virus scans, game modifications, etc. Windows2000 is a fully protected system and has two working modes, namely User Model and Kernel Models. Memory scans can also be divided into user-state memory scans and core state memory scans. This paper mainly describes the memory scan for user-state. One. Related theory

Memory scanning under the neutrality of DOS is a relatively simple thing. Because DOS works in the real mode of the CPU, there is no memory technology to provide memory technology. As long as it is real scanning all physical memory, everything is completed, and there are some anti-virus software in the early days. Such a way. Of course, in order to improve efficiency, we don't have to scan all memory areas, because some space is not used, and scanning these places is only wasting time. This can be used to obtain the actual memory usage area of ​​the MCB chain of the DOS system, so that the efficiency of the scan is greatly improved. Similar ideas are also applicable to memory scans under Windows2000.

Windows2000 is a fully protected system that is induced in the protection mode of the CPU. Each process has an independent 4GB address space, where low 2GB is a private space of the process, high 2GB is a system space map (if you use "/ 3GB" in the boot.ini file, you can make the process private space Increase to 3GB, system space 1GB). For each process, its virtual address space is continuous. In fact, they are discrete in units of pages in physical memory, some of which may be swapped to a page file on the hard disk, and most of the space It is uncommitted. Therefore, the user space for the process in Windows 2000 must be scanned in turn to scan the space of each process. The low 2GB of a process is spaced in the following table:

Range size 0x0 ~~ 0xfffff / 64 KB Unsable area, just to prevent illegal pointer access, access to this range of addresses will cause access to violations. 0x10000 ~~

0x7ffeffff 2 GB minus the private address space of at least 192 kb processes 0x7ffde000 ~~

0x7ffdeffff 4 KB process thread environment block, TEB (Thread Environment Block) 0x7ffdf000 ~~ 0x7ffdffff 4 KB process process environment block, ie PEB (Process Environment Block)

0x7ffe0000 ~~

0x7ffe0FFF 4 KB A shared read-only user data block that maps to a data block to the system space, where some system information such as system time, ticks, system version number, etc. When such information is accessed, the system does not switch to the core mode. 0x7ffe1000 ~~

0x7ffeffff 60 KB is not accessible 0x7FFF0000 ~~ 0x7fffffff 64 KB is not accessible, the boundary table 1 for preventing threads from buffering spanning two mode space

two. It can be seen from the above table that we have to scan the range of starting points and end points from 0 to ~ 2GB, but only part of it. To obtain the start and end of the GetSystemInfo may use the API function, the following function prototype: VOID GetSystemInfo (LPSYSTEM_INFO lpSystemInfo // system information); the two domains in the structure SYSTEM_INFO: lpMinimumApplicationAddress and lpMaximumApplicationAddress (types are LPVOID), we have You can get the minimum and maximum address space available for an application. In this way, we get the starting and end point of the address to be scanned. So, is it to scan all the addresses between this starting point and the end point? This is not the case, because the next process is not such a large (close to 2GB) address space. Therefore, most of the address spaces of a process are unused or reserved, which is truly used is only those submitted. Memory page can have three states: unused, reservoid, and committed. An unused page refers to the page is not retained or submitted. It is unavailable to a process to access such a page will result in access to violations. The process can require the system to retain some pages for use, the system returns a reserved address to the process, but these addresses are also inaccessible, and the process must be submitted before using this address space. Only one submitted page is a page that is actually accessible. However, you submit a page, the system does not immediately allocate the physical page, and the system will allocate the page and initialize only when the page is first accessed. In addition, both two of these three states can be transformed with each other. Related API functions have Virtualalloc, VirtualaLocex, VirtualFree, VirtualFreex, and so on. So our work has been greatly reduced, just scanning those submitted pages. The next thing to do is to get the submitted page range of a process. This is to use two other API functions VirtualQuery and VirtualQueryex. The functionality of the two functions is similar. Differently, VirtualQuery just queries the process and VirtualQueryex can query the memory space information of the specified process, the latter is what we need, the function prototype is as follows: DWord VirtualqueryEx (Handle HProcess, // Handle to Process LPCVOID LPADDRESS, / / ​​Address of Region PMemory_basic_information lpbuffer, // information buffer size_t dwlength // size of buffer; the first parameter is the handle of the process; the second parameter is the memory address pointer; the third parameter is to the Memory_basic_information structure The pointer is used to return information of memory space; the fourth parameter is the length of LPBuffer.

Then look at the structure MEMORY_BASIC_INFORMATION statement: typedef struct _MEMORY_BASIC_INFORMATION {PVOID BaseAddress; PVOID AllocationBase; DWORD AllocationProtect; SIZE_T RegionSize; DWORD State; DWORD Protect; DWORD Type;} MEMORY_BASIC_INFORMATION, * PMEMORY_BASIC_INFORMATION; The first parameter is the base address of the memory block query The second parameter refers to the base address that is actually allocated when the memory is assigned by Virtualalloc, which is less than baseaddress, that is, BaseEaddress must be included within the range of allocationBase assignments; the third parameter refers to the page, page Some properties such as Page_Readwrite, Page_Execute, etc. (other properties can be referred to Platform SDK); the fourth parameter refers to the size of the page starting from BaseAddress, with the same properties. The fifth parameter refers to the state of the page, there are three possible values: MEM_COMMIT, MEM_FREE and MEM_RESERVE, this parameter is the most important for us, from which we can know the state of the designated memory page; the sixth parameters refers to It is the attribute of the page, which may be the same as allocationProtect; the last parameter indicates the type of the memory block, there are three possible values: MEM_IMAGE, MEM_MAPPED, and MEM_PRIVATE. This way we can get the range of addresses that need to be scanned in the process. The remaining problem here is to read the contents of the designated address space specified by the specified process. It is useful here that an API function for debugging and error handling is used.

In the "Platform SDK: Debugging and Error Handling", a part of the API function associated with program debugging and error handling is available, and there are many useful, such as the ReadProcessMemory and WriteProcessMemory we used below, whose prototype is as follows: BOOL ReadProcessMemory hANDLE hProcess, // handle to the process LPCVOID lpBaseAddress, // base of memory area LPVOID lpBuffer, // data buffer SIZE_T nSize, // number of bytes to read SIZE_T * lpNumberOfBytesRead // number of bytes read); BOOL WriteProcessMemory (hANDLE hProcess, // handle to process LPVOID lpBaseAddress, // base of memory area LPCVOID lpBuffer, // data buffer SIZE_T nSize, // count of bytes to write SIZE_T * lpNumberOfBytesWritten // count of bytes written); parameters from their easy The name can guess its meaning, not much explanation here. To illustrate, you want to perform a READPROCESSMORY operation, the current process must have Process_VM_READ access to the process to read. To perform WRITEPROCESSMORY operations for a process, the current process must have Process_VM_WRITE and Process_VM_Operation access. To get a process handler and some of the controls for this process, you can use the API function OpenProcess to get it. It doesn't make a detailed description, just give its prototype: Handle OpenProcess (DWord DwdesiredAccess, // Access Flag Bool BinheritHandle, // Handle Inheritance Option DWord DWProcessID // Process Identifier); This process is basically clearly described so that the process of user address space memory scan for a process is basically clear.

Three related questions:

Some problems will encounter in actual operations. If we specify write-related access (such as Process_VM_WRITE, Process_Set_information, Process_all_Access, etc.) Open some normal processes with openprocess, but if you open the system security process (such as System, Winlogon, SMSS, CSRSS, Services, LSASS Wait, when some registration is a service process, it will encounter an "access rejection" error, which is the protection tool for system security. The current process does not have sufficient permissions to do this. There is a "access token" in the process control structure, which contains the permissions information of this process. Some common permissions are shown in Table 1 (taken from inside windows2000, third edition).

Permissions Name Permissions Meaning Sebackup In Backup, Windebug can debug SEDEBUG for a process. SESHUTDOWN can turn off local system SetakeowNERSHIP without free access to ownership of all rights Form 2

To specify an arbitrary process (including system security processes and service processes), the OpenProcess operation written to write-related access, as long as the current process has Sededebug permission. If a user is administrator or the corresponding permissions, it can have this permission. However, even if we use the Administrator account to perform openprocess (Process_Access, false, dwprocessid), which will also encounter an "access rejection" error with the Administrator account. What is the reason? It turns out that some access rights of the process in the default case are not enabled, so we must do these privileges first. Some of the API functions associated with this include OpenProcessToken, LookuppprivileValue, AdjustTokenPrivileges. We want to modify the access token of a process, first get the handle of the process to access the token, which can be obtained by OpenProcessToken, the prototype of the function is as follows:

Bool OpenProcessToken (Handle ProcessHandle, DWord "; The first parameter is to modify the process handle of the access rights; the third parameter is the return token pointer returned; the second parameter specifies the type of operation you want to do, such as To modify the token We want to specify the second parameter to beken_adjust_privileges (other parameters can be referred to Platform SDK). Through this function we can get the handle of the token of the current process (the first parameter of the specified function is possible). Then we can call AdjustTokenPrivileges to modify this access token. AdjustTokenPrivileges following prototype: BOOL AdjustTokenPrivileges (HANDLE TokenHandle, // handle to token BOOL DisableAllPrivileges, // disabling option PTOKEN_PRIVILEGES NewState, // privilege information DWORD BufferLength, // size of buffer PTOKEN_PRIVILEGES PreviousState, // original state buffer PDWORD ReturnLength // Required buffer size); the first parameter is the handle of the token; the second parameter decision is permission to modify or except for all rights; the third parameter indicates the permissions to modify, is a point to the Token_Privileges structure Pointer, the structure contains an array, each item of the data group indicates the type of permissions and the operation to be performed; the fourth parameter is the length of the structure previousstate, if previouState is empty, the parameter should be null; fifth parameters It is also a pointer to the Token_PrivilegeS structure, store information for access before modification, can be exposed; the last parameter is the size returned by the actual PreviouState structure. Before using this function TOKEN_PRIVILEGES look at the structure, which statement is as follows: typedef struct _TOKEN_PRIVILEGES {DWORD PrivilegeCount; LUID_AND_ATTRIBUTES Privileges [];} TOKEN_PRIVILEGES, * PTOKEN_PRIVILEGES; refers to an array of the original number PrivilegeCount pigment, followed by a type of LUID_AND_ATTRIBUTES Array, let's take a look at the content of Luid_and_attributes, the declaration is as follows:

Typedef struct _luid_and_attributes {Luid Luid; DWORD ATTRIBUTES;} Luid_and_attributes, * pluid_and_attributes

The second parameter indicates the type of operation we have to perform, there are three options: SE_PRIVILE_ENABED, SE_PRIVILE_ENABLED_BY_DEFAULT, SE_PRIVILE_USED_FOR_ACCESS. To enable a permission to specify attributes for SE_PRIVILE_ENABLED. The first parameter refers to the type of rights. It is a value of Luid. LUID means that the GUID is more familiar, and the GUID requirements guarantee the only difference between the global, and Luid is guaranteed to be partially unique. Each running period of the system is guaranteed is the only one. In addition, the same point as Guid, Luid is also a 64-bit value, I believe everyone has seen the big string of guid, how can we know how much the LUID value corresponds to a permission? This use to another API function LookupPrivilegeValue, which prototype is as follows: BOOL LookupPrivilegevalue (LPCTSTR lpSystemName, // system name LPCTSTR lpName, // privilege name PLUID lpLuid // locally unique identifier); The first argument is the name of the system, If the local system is specified as null, the third parameter is the pointer to Luid, and the second parameter is the name of the permissions, such as "SedebugPrivilege". A macro of some permissions names are also defined in Winnt.h, such as:

#define se_backup_name text ("Sebackupprivilege")

#define se_restore_name text ("SerestorePrivilege")

#define se_shutdown_name text ("SESHUTDOWNPRIVILEGE")

#define se_debug_name text ("SedebugPrivilege")

Through the call of these three functions, we can use OpenProcess (Process_Access, false, dwprocessid) to get the handle of any process and assign all access rights. Summary

The memory scan of the user mode is still the limitations, which cannot fully scan all the memory spaces of Windows2000. To scan the system space, under Windows2000, the user mode application cannot be implemented. To achieve a scan for system space, you must implement by a program-driver working on a core mode.

A few days ago, my friend told me to help it make a game modifier, I remembered this article, but I finally found it, I feel good, provide to everyone to see the original posted by http://expert.9cbs.net/Expert/topic / 1374/1374047.xml?temp=.4722254

转载请注明原文地址:https://www.9cbs.com/read-24668.html

New Post(0)