今天发现一个问题,算是细节 如果有知道的请讲解一下 MEMORY_BASIC_INFORMATION mbi;
BOOL bOk = (VirtualQueryEx(hProcess, pvAddress, &mbi, sizeof(mbi))
== sizeof(mbi));
得到内存信息此时
mbi.State 是MEM_COMMIT并且 mbi.Protect 为 PAGE_EXECUTE_READ
也就是此块的内存是 读取和执行权限 但是我们用WriteProcess 完全可以写此处的内存 虽然核心编程中的操作是失败的话就修改内存属性为PAGE_EXECUTE_READWRITE 然后尝试写操作我的问题就是 为什么没有写权限的内存块却可以执行写操作
BOOL bOk = (VirtualQueryEx(hProcess, pvAddress, &mbi, sizeof(mbi))
== sizeof(mbi));
得到内存信息此时
mbi.State 是MEM_COMMIT并且 mbi.Protect 为 PAGE_EXECUTE_READ
也就是此块的内存是 读取和执行权限 但是我们用WriteProcess 完全可以写此处的内存 虽然核心编程中的操作是失败的话就修改内存属性为PAGE_EXECUTE_READWRITE 然后尝试写操作我的问题就是 为什么没有写权限的内存块却可以执行写操作
MEM_COMMIT 指明已分配物理内存或者系统页文件。
MEM_FREE 空闲状态。该区域的虚拟地址不受任何内存的支持。该地址空间没
有被保留。改状态下AllocationBase、AllocationProtect、Protect
和Type等成员均未定义。
MEM_RESERVE 指明页面被保留,但是没有分配任何物理内存。该状态下Protect成
员未定。这个域跟读写无关,你理解大大的错误。要看可读可写,你应该看AllocationProtect 这个域
原来WriteProcessMemory不会考虑内存的保护属性,这样说的话估计内存保护属性是为了帮助程序员自己发现失误的操作吧. int *p 指向一个 没有写操作权限的内存的时候确实无法给内容赋值
难道Windows核心编程和Programming Applications for Microsoft Windows不是同一本书?
是吧 我的是第五版 书名叫 Windows via c/c++ 这是核心编程中一个例子中 修改内存的代码 if (!WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew,
sizeof(pfnNew), NULL) && (ERROR_NOACCESS == GetLastError())) {
DWORD dwOldProtect;
if (VirtualProtect(ppfn, sizeof(pfnNew), PAGE_WRITECOPY,
&dwOldProtect)) { WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew,
sizeof(pfnNew), NULL);
VirtualProtect(ppfn, sizeof(pfnNew), dwOldProtect,
&dwOldProtect);
}如果“WriteProcessMemory 不受内存保护属性限制” 成立 并且Windows核心编程提到此内容 代码中的
ERROR_NOACCESS == GetLastError() 就没有必要了,此句话的意思是 判断WriteProcessMemory失败的原因是不是因为拒绝访问,也就是写权限不够
期待一下写轮兔更深的理解
.text:7C80220F public WriteProcessMemory
.text:7C80220F WriteProcessMemory proc near
.text:7C80220F
.text:7C80220F lpPageStartAddress= dword ptr -8
.text:7C80220F lpPageSize = dword ptr -4
.text:7C80220F hProcess = dword ptr 8
.text:7C80220F lpBaseAddress = dword ptr 0Ch
.text:7C80220F lpBuffer = dword ptr 10h
.text:7C80220F nSize = dword ptr 14h
.text:7C80220F lpNumberOfBytesWritten= dword ptr 18h
.text:7C80220F
.text:7C80220F mov edi, edi ;
.text:7C802211 push ebp
.text:7C802212 mov ebp, esp
.text:7C802214 push ecx
.text:7C802215 push ecx
.text:7C802216 mov eax, [ebp+lpBaseAddress]
.text:7C802219 push ebx ;
.text:7C802219 ;
.text:7C80221A mov ebx, [ebp+nSize]
.text:7C80221D push esi ;
.text:7C80221E mov esi, ds:NtProtectVirtualMemory
.text:7C802224 push edi ;
.text:7C802225 mov edi, [ebp+hProcess]
.text:7C802228 mov [ebp+lpPageStartAddress], eax
.text:7C80222B lea eax, [ebp+nSize] ; 这里让nSize偏移处保持旧的access值
.text:7C80222E push eax
.text:7C80222F push 40h ; PAGE_EXECUTE_READWRITE,亮点
.text:7C802231 lea eax, [ebp+lpPageSize]
.text:7C802234 push eax
.text:7C802235 lea eax, [ebp+lpPageStartAddress]
.text:7C802238 push eax
.text:7C802239 push edi
.text:7C80223A mov [ebp+lpPageSize], ebx
.text:7C80223D call esi ; NtProtectVirtualMemory
.text:7C80223F cmp eax, 0C000004Eh ; STATUS_SECTION_PROTECTION
.text:7C80223F ;
.text:7C80223F ; 这里没有执行权限
.text:7C802244 jz short lblDontHaveExecuteRights
.text:7C802246
.text:7C802246 lblTestMemoryAccess: ; CODE XREF: WriteProcessMemory+A4j
.text:7C802246 test eax, eax
.text:7C802248 jl short lblNoteError
.text:7C80224A mov eax, [ebp+nSize]
.text:7C80224D test al, 0CCh ; 这里做位与判断,和我们判断页权限的代码相同,这里做了实现:
.text:7C80224D ;
.text:7C80224D ; PAGE_EXECUTE_READWRITE |
.text:7C80224D ; PAGE_READWRITE |
.text:7C80224D ; PAGE_EXECUTE_WRITECOPY |
.text:7C80224D ; PAGE_WRITECOPY
.text:7C80224D ;
.text:7C80224D ;
.text:7C80224F jz short lblNotMMF_OrShared ; 判断是否和旧 access值相同
.text:7C80224F ;
.text:7C80224F ; PAGE_NOACCESS |
.text:7C80224F ; PAGE_READONLY
.text:7C802251 lea ecx, [ebp+nSize] ; 恢复旧的 access
.text:7C802251 ;
.text:7C802254 push ecx
.text:7C802255 push eax
.text:7C802256 lea eax, [ebp+lpPageSize]
.text:7C802259 push eax
.text:7C80225A lea eax, [ebp+lpPageStartAddress]
.text:7C80225D push eax
.text:7C80225E push edi
.text:7C80225F call esi ; NtProtectVirtualMemory 亮点哦
.text:7C802261 lea eax, [ebp+hProcess]
.text:7C802264 push eax
.text:7C802265 push ebx
.text:7C802266 push [ebp+lpBuffer]
.text:7C802269 push [ebp+lpBaseAddress]
.text:7C80226C push edi
.text:7C80226D call ds:NtWriteVirtualMemory ;再写
.text:7C802273 mov ecx, [ebp+lpNumberOfBytesWritten]
.text:7C802276 test ecx, ecx
.text:7C802278 jnz loc_7C80231C
.text:7C80227E
.text:7C80227E lblTestIfMMF_OrSharedWriteFailed: ; CODE XREF: WriteProcessMemory+112j
.text:7C80227E test eax, eax
.text:7C802280 jl short lblNoteError
.text:7C802282
.text:7C802282 lblFlushInstructions: ; CODE XREF: WriteProcessMemory+E1j
.text:7C802282 push ebx
.text:7C802283 push [ebp+lpBaseAddress]
.text:7C802286 push edi
.text:7C802287 call ds:NtFlushInstructionCache 这个地方熟悉吧?刷缓存
.text:7C80228D xor eax, eax
.text:7C80228F inc eax
.text:7C802290
.text:7C802290 lblExitNoError: ; CODE XREF: WriteProcessMemory+108j
.text:7C802290 ; WriteProcessMemory+119j
.text:7C802290 pop edi ;
.text:7C802291 pop esi
.text:7C802292 pop ebx
.text:7C802293 leave
.text:7C802294 retn 14h
.text:7C802297 ; ---------------------------------------------------------------------------
.text:7C802297
.text:7C802297 lblNoteError: ; CODE XREF: WriteProcessMemory+39j
.text:7C802297 ; WriteProcessMemory+71j
.text:7C802297 push eax
.text:7C802298 call sub_7C80936B ; 这个函数把错误码转换为系统错误并将其放在TEB里面
.text:7C802298 ;
.text:7C802298 ;
.text:7C80229D jmp lblFail ; 错误了
.text:7C8022A2 ; ---------------------------------------------------------------------------
.text:7C8022A2
.text:7C8022A2 lblDontHaveExecuteRights: ; CODE XREF: WriteProcessMemory+35j
.text:7C8022A2 lea eax, [ebp+nSize]
.text:7C8022A5 push eax
.text:7C8022A6 push 4 ; PAGE_READWRITE
.text:7C8022A8 lea eax, [ebp+lpPageSize]
.text:7C8022AB push eax
.text:7C8022AC lea eax, [ebp+lpPageStartAddress]
.text:7C8022AF push eax
.text:7C8022B0 push edi
.text:7C8022B1 call esi ; NtProtectVirtualMemory
.text:7C8022B3 jmp short lblTestMemoryAccess
.text:7C8022B5 ; ---------------------------------------------------------------------------
.text:7C8022B5
.text:7C8022B5 lblNotMMF_OrShared: ; CODE XREF: WriteProcessMemory+40j
.text:7C8022B5 test al, 3 ; 判断access值:
.text:7C8022B5 ; PAGE_NOACCESS |PAGE_READONLY
.text:7C8022B7 jnz short lblPageNoAccessOrReadOnly ; 跳还是不跳?
.text:7C8022B9 lea eax, [ebp+hProcess]
.text:7C8022BC push eax
.text:7C8022BD push ebx ; nSize
.text:7C8022BE push [ebp+lpBuffer]
.text:7C8022C1 push [ebp+lpBaseAddress]
.text:7C8022C4 push edi ; hProcess
.text:7C8022C5 call ds:NtWriteVirtualMemory ; 写
.text:7C8022CB mov [ebp+lpBuffer], eax
.text:7C8022CE mov eax, [ebp+lpNumberOfBytesWritten]
.text:7C8022D1 test eax, eax
.text:7C8022D3 jz short lblRestoreOldAccess
.text:7C8022D5 mov ecx, [ebp+hProcess]
.text:7C8022D8 mov [eax], ecx
.text:7C8022DA
.text:7C8022DA lblRestoreOldAccess: ; CODE XREF: WriteProcessMemory+C4j
.text:7C8022DA lea eax, [ebp+nSize]
.text:7C8022DD push eax ; &nSize
.text:7C8022DE push [ebp+nSize] ; 恢复旧的access值
.text:7C8022E1 lea eax, [ebp+lpPageSize]
.text:7C8022E4 push eax
.text:7C8022E5 lea eax, [ebp+lpPageStartAddress]
.text:7C8022E8 push eax
.text:7C8022E9 push edi
.text:7C8022EA call esi ; NtProtectVirtualMemory
.text:7C8022EC cmp [ebp+lpBuffer], 0
.text:7C8022F0 jge short lblFlushInstructions
.text:7C8022F2 mov esi, 0C0000005h ; STATUS_ACCESS_VIOLATION
.text:7C8022F7 jmp short lblThrowAccessViolation
.text:7C8022F9
.text:7C8022F9 lblPageNoAccessOrReadOnly: ; CODE XREF: WriteProcessMemory+A8j
.text:7C8022F9 lea ecx, [ebp+nSize] ; 恢复旧的 access等级
.text:7C8022FC push ecx
.text:7C8022FD push eax
.text:7C8022FE lea eax, [ebp+lpPageSize]
.text:7C802301 push eax
.text:7C802302 lea eax, [ebp+lpPageStartAddress]
.text:7C802305 push eax
.text:7C802306 push edi
.text:7C802307 call esi ; NtProtectVirtualMemory
.text:7C802309 xor esi, esi
.text:7C80230B
.text:7C80230B lblThrowAccessViolation: ; CODE XREF: WriteProcessMemory+E8j
.text:7C80230B push 0C0000005h
.text:7C802310 call sub_7C80936B
.text:7C802315 mov eax, esi
.text:7C802317 jmp lblExitNoError ; 清理现场
.text:7C80231C ; ---------------------------------------------------------------------------
.text:7C80231C
.text:7C80231C loc_7C80231C: ; CODE XREF: WriteProcessMemory+69j
.text:7C80231C mov edx, [ebp+hProcess]
.text:7C80231F mov [ecx], edx
.text:7C802321 jmp lblTestIfMMF_OrSharedWriteFailed
.text:7C802326 ; ---------------------------------------------------------------------------
.text:7C802326
.text:7C802326 lblFail: ; CODE XREF: WriteProcessMemory+8Ej
.text:7C802326 xor eax, eax ; 错误!
.text:7C802328 jmp lblExitNoError ; 清理现场
.text:7C802328 WriteProcessMemory endp在你向一个保护的Section里面写发生错误的时候,WriteProcessMemory会调用NtProcectVirtualMemory尝试修改access为PAGE_READWRITE,因为需要执行。这就是前面cnzdgs大牛所说的类似意思吧。如果NtProtectVirtualMemory的调用也是白,系统在TEB保存一个access验证错误的码,然后函数返回0。最后,假设所有调用都成功了,NtProtectVirtualMemory也没有失败,WriteProcessMemory开始检查原来的access,就是原来存在nSize的那个地方的那个。这个时候一个恶心的系统特性就出来了,如果原来就是PAGE_EXECUTE_READWRITE | PAGE_READWRITE | PAGE_EXECUTE_WRITECOPY | PAGE_WRITECOPY系统也会给你降到PAGE_NOACCESS | PAGE_READONLY!
这么说 WriteProcessMemory还是会收到 保护属性的影响 但他会自动尝试修改?
至于 降到PAGE_NOACCESS | PAGE_READONLY 是什么意思int main()
{
DWORD flProtect = PAGE_EXECUTE_READ;//此处不能有 WRITECOPY属性 否则VirtualAlloc 将失败
printf("测试属性 :%x\n",flProtect);
void *myMemory = VirtualAlloc(NULL,1024*4,MEM_RESERVE|MEM_COMMIT,flProtect); MEMORY_BASIC_INFORMATION mbi;
BOOL bOk = (VirtualQuery(myMemory,&mbi,sizeof(mbi)) == sizeof(mbi)); printf("初始属性 :%x\n",mbi.Protect); WriteProcessMemory(GetCurrentProcess(),myMemory,"abc",sizeof("abc"),NULL); bOk = (VirtualQuery(myMemory,&mbi,sizeof(mbi)) == sizeof(mbi));
printf("之后 :%x\n",mbi.Protect);
return 0;
}我测试了几种属性 没有改变啊