Windows核心编程中的 关于内存写权限的问题

yxwsbobo 2010-06-01 05:25:31
今天发现一个问题,算是细节 如果有知道的请讲解一下

   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 然后尝试写操作

我的问题就是 为什么没有写权限的内存块却可以执行写操作
...全文
404 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
magic7004 2010-06-02
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 yxwsbobo 的回复:]

引用 16 楼 magic7004 的回复:

晕,楼主不是在看核心编程吗?怎么不知道WriteProcessMemory的问题呢?在DLL注入那章就有说到这个问题的。

我有9成把握 书中没有说此问题

[/Quote]

难道Windows核心编程和Programming Applications for Microsoft Windows不是同一本书?
cnzdgs 2010-06-02
  • 打赏
  • 举报
回复
内存保护类型是对本进程中程序操作内存的限制,WriteProcessMemory不受此限制。因为WriteProcessMemory的主要目的是调试程序,所以只要是可执行的内存,都允许改写。
yxwsbobo 2010-06-02
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 magic7004 的回复:]

晕,楼主不是在看核心编程吗?怎么不知道WriteProcessMemory的问题呢?在DLL注入那章就有说到这个问题的。
[/Quote]
我有9成把握 书中没有说此问题




原来WriteProcessMemory不会考虑内存的保护属性,这样说的话估计内存保护属性是为了帮助程序员自己发现失误的操作吧. int *p 指向一个 没有写操作权限的内存的时候确实无法给内容赋值
magic7004 2010-06-02
  • 打赏
  • 举报
回复
晕,楼主不是在看核心编程吗?怎么不知道WriteProcessMemory的问题呢?在DLL注入那章就有说到这个问题的。
MoXiaoRab 2010-06-02
  • 打赏
  • 举报
回复
结贴结贴,分拿来
wltg2001 2010-06-02
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 cnzdgs 的回复:]
内存保护类型是对本进程中程序操作内存的限制,WriteProcessMemory不受此限制。因为WriteProcessMemory的主要目的是调试程序,所以只要是可执行的内存,都允许改写。
[/Quote]
原来如此,我疑惑了很长时间了。
yxwsbobo 2010-06-02
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 tr0j4n 的回复:]

引用 23 楼 yxwsbobo 的回复:
前两天 刚把汇编学了 单独的一句指令看得懂 连起来就完全不知道什么意思了




这么说 WriteProcessMemory还是会收到 保护属性的影响 但他会自动尝试修改?


至于 降到PAGE_NOACCESS | PAGE_READONLY 是什么意思



C/C++ code

int main()
{
D……
[/Quote]


这要怪你以 降到PAGE_NOACCESS | PAGE_READONLY! 结尾啊 逆向出的代码只看的懂中文

你逆向用的软件吗 还是直接反汇编自己写的



我正看驱动呢 看完这块 回来好好品品
MoXiaoRab 2010-06-02
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 yxwsbobo 的回复:]
前两天 刚把汇编学了 单独的一句指令看得懂 连起来就完全不知道什么意思了




这么说 WriteProcessMemory还是会收到 保护属性的影响 但他会自动尝试修改?


至于 降到PAGE_NOACCESS | PAGE_READONLY 是什么意思



C/C++ code

int main()
{
DWORD flProtect = PAG……
[/Quote]
WriteProcessMemory调用完毕,access属性已经恢复了好吧~~~

你理解能力真差
yxwsbobo 2010-06-02
  • 打赏
  • 举报
回复
前两天 刚把汇编学了 单独的一句指令看得懂 连起来就完全不知道什么意思了




这么说 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;
}



我测试了几种属性 没有改变啊
MoXiaoRab 2010-06-02
  • 打赏
  • 举报
回复
.text:7C8022F9 ; ---------------------------------------------------------------------------
.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!
MoXiaoRab 2010-06-02
  • 打赏
  • 举报
回复
对WriteProcessMemory进行逆向,结果如下

.text:7C80220F ; BOOL __stdcall WriteProcessMemory(HANDLE hProcess,LPVOID lpBaseAddress,LPVOID lpBuffer,DWORD nSize,LPDWORD lpNumberOfBytesWritten)
.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
yxwsbobo 2010-06-02
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 magic7004 的回复:]

引用 17 楼 yxwsbobo 的回复:

引用 16 楼 magic7004 的回复:

晕,楼主不是在看核心编程吗?怎么不知道WriteProcessMemory的问题呢?在DLL注入那章就有说到这个问题的。

我有9成把握 书中没有说此问题



难道Windows核心编程和Programming Applications for Microsoft Windows不……
[/Quote]

是吧 我的是第五版 书名叫 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失败的原因是不是因为拒绝访问,也就是写权限不够




期待一下写轮兔更深的理解
MoXiaoRab 2010-06-02
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 yxwsbobo 的回复:]
引用 16 楼 magic7004 的回复:

晕,楼主不是在看核心编程吗?怎么不知道WriteProcessMemory的问题呢?在DLL注入那章就有说到这个问题的。

我有9成把握 书中没有说此问题




原来WriteProcessMemory不会考虑内存的保护属性,这样说的话估计内存保护属性是为了帮助程序员自己发现失误的操作吧. int *p 指向一个 没有写操作权限的……
[/Quote]
你别忙结这个贴。

我下午下课的时候给你写点分析的东西
MoXiaoRab 2010-06-01
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 tr0j4n 的回复:]
mbi.State 是MEM_COMMIT
并且 mbi.Protect 为 PAGE_EXECUTE_READ
也就是此块的内存是 读取和执行权限

能执行,没说不能写[/Quote]

上自习刚回来。

等下,我貌似下午题目看得太匆忙了,回答得不准确

现在重新回答下。

PAGE_EXECUTE_READ确实是有可写的权限的。
wltg2001 2010-06-01
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 oyljerry 的回复:]
看你的对应内存数据是否正确写入了...估计没成功.
[/Quote]
我也这么怀疑,不过,以前有个用DELPHI的,用WriteProcessMemory直接写代码段成功的,他都没意识到权限的问题。
oyljerry 2010-06-01
  • 打赏
  • 举报
回复
看你的对应内存数据是否正确写入了...估计没成功.
Eleven 2010-06-01
  • 打赏
  • 举报
回复
MSDN:

PAGE_EXECUTE_READ 0x20

Enables execute and read access to the committed region of pages. An attempt to write to the committed region results in an access violation.

soswaidao 2010-06-01
  • 打赏
  • 举报
回复
PAGE_EXECUTE_READ 意味着 只读,并不是 执行与读
iqyely 2010-06-01
  • 打赏
  • 举报
回复
关注下。
wltg2001 2010-06-01
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 tr0j4n 的回复:]
mbi.State 是MEM_COMMIT
并且 mbi.Protect 为 PAGE_EXECUTE_READ
也就是此块的内存是 读取和执行权限

能执行,没说不能写[/Quote]
PAGE_EXECUTE_READ
0x20 Enables execute and read access to the committed region of pages. An attempt to write to the committed region results in an access violation.
我也觉得应该是执行与读权限,不过我英语很烂
加载更多回复(6)

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧