能力值:
( LV6,RANK:80 )
|
-
-
2 楼
哎……悲剧了 =。-
|
能力值:
( LV9,RANK:610 )
|
-
-
3 楼
句柄是不是有效,得看在哪个进程里,别的进程里的有效句柄在别一个进程里不一定有效
|
能力值:
( LV6,RANK:80 )
|
-
-
4 楼
嘿嘿,回教主……你指的进程句柄表吧,其实它返回的错误是无效句柄,但是和我传入的参数无关的……按照reactOS的源码,是在第一个分支,验证 if(hwndParent || !dwThreadId)里才会返回无效句柄的,那样是和hDesk , hwndParent 的有效性有关,但是我两者都设为0,dwThreadId为非0,所以根本就不会进入第一个分支,更不应该返回无效句柄错误了……这才是我郁闷的地方。
我把那部分代码弄到应用层去,再传给驱动试试……我监视过,应用层的EnumThreadWindows调用是木有问题的,而且传参方式和我的一样的
无论如何,谢教主的回复咯~ 大家都不理我
|
能力值:
( LV9,RANK:610 )
|
-
-
5 楼
发重复了。。。
最好的办法还是自己调试吧~~
|
能力值:
( LV9,RANK:610 )
|
-
-
6 楼
ReactOS里面的代码只能当做参考,离真正的Win代码还有很多差距呢~~
我看了一下,错误可能出在下面这个地方,希望对你有点帮助
NTSTATUS __stdcall ValidateHdesk(HANDLE Handle, KPROCESSOR_MODE Object, ACCESS_MASK DesiredAccess, int a4)
{
int v4; // eax@1
NTSTATUS laststatus; // edi@1
int v6; // esi@1
NTSTATUS status; // eax@1
char v9; // sf@1
status = ObReferenceObjectByHandle(
Handle,
DesiredAccess,
(POBJECT_TYPE)ExDesktopObjectType,
Object,
(PVOID *)&Object,
0);
v6 = a4;
laststatus = status;
v9 = status < 0;
v4 = Object;
*(_DWORD *)a4 = Object;
if ( v9 )
{
SetLastNtError(laststatus);
}
else
{
if ( *(_DWORD *)v4 != gSessionId || *(_BYTE *)(v4 + 23) & 0xE0 )
{
laststatus = 0xC0000008u;
SetLastNtError(0xC0000008u);
ObfDereferenceObject(*(PVOID *)v6);
}
}
return laststatus;
}
|
能力值:
( LV9,RANK:610 )
|
-
-
7 楼
终于搞定这个问题了~~
根本原因是NtUserBuildHwndList的最后两个参数必须是ring3地址!
text:BF830E80 loc_BF830E80: ; CODE XREF: sub_BF830D9F-31j
.text:BF830E80 push 4 ; Alignment
.text:BF830E82 mov eax, edi
.text:BF830E84 shl eax, 2
.text:BF830E87 push eax ; Length
.text:BF830E88 push dword ptr [ebp+1Ch] ; Address
.text:BF830E8B call ds:ProbeForWrite(x,x,x) //对HwndBuffer验证
.text:BF830E8B
.text:BF830E91 mov edx, [ebp+20h] ; pBufSize
.text:BF830E94 mov eax, _Win32UserProbeAddress //0x7fff0000
.text:BF830E99 cmp edx, eax
.text:BF830E9B jnb loc_BF830D73 ; 若传入的是内核地址,这时将会跳走,然后产生异常
以上就是NtUserBuildHwndList中对参数的验证,对倒数第二个参数使用ProbeForWrite进行检查,显然这必须是一个ring3地址才行。如果检查未通过将产生异常,在异常处理函数里有如下代码:
.text:BF830D9F sub_BF830D9F proc near ; DATA XREF: .rdata:BF98B2F8o
.text:BF830D9F
.text:BF830D9F ; FUNCTION CHUNK AT .text:BF830D38 SIZE 00000050 BYTES
.text:BF830D9F ; FUNCTION CHUNK AT .text:BF830EE9 SIZE 00000063 BYTES
.text:BF830D9F
.text:BF830D9F mov esp, [ebp-18h]
.text:BF830DA2 mov edi, 0C0000008h //0xC0000008状态码在这儿
.text:BF830DA7 or dword ptr [ebp-4], 0FFFFFFFFh
.text:BF830DAB mov esi, [ebp-20h]
.text:BF830DAE jmp loc_BF830EC5 //跳回原函数的收尾部分,edi将赋值给eax,即返回值NTSTATUS
正是以上代码导致了0xC0000008错误码的产生,而不是我上面说的那个检查DesktopHandle的函数。
而接下会对最后一个参数也会进行检查,要求必须小于Win32UserProbeAddress,也就是0x7fff0000,如果这里不满足就会跳走,然后程序会访问0x7fff0000产生一个异常,异常后同样会跳到上面的异常处理代码中,最后产生一个0xC0000008的状态码。
经我测试,把最后两个地址改成ring3的地址就可以成功了,这个地址可以由ring3传来,也可以使用ZwAllocateVirtuelMemory申请,总之是ring3的地址就行了~~
后面附上我的一个测试代码.
使用方法:打开DbgView,先加载驱动,然后运行exe,点击"Help"->"About",程序将会向驱动发送一个DeviceIoControl,然后就可以查看结果了~
ps:大概只有我这么蛋疼的人才会花这么多时间去解决这么一个蛋疼的问题吧。。。
不过更蛋疼的是为什么NtUserBuildHwndList会先去BuildHwndList,然后才会检查传入的参数啊。。。
发现参数不正确,然后再FreeHwndList,早知如此,何必当初呢?真是蛋疼的很~~
而且参数不正确的话,为什么返回的是0xC0000008而不是0xC000000D(STATUS_INVALID_PARAMETER)之类呢?
|
能力值:
( LV6,RANK:80 )
|
-
-
8 楼
哈哈,葱白下你的反汇编功底~ 我也反过那个函数,但是看着看着就趴着睡着了。
我改改,把代码修正下~不过看起来的确是个很蛋疼的问题,谢教主了
|
能力值:
( LV9,RANK:610 )
|
-
-
9 楼
想起来了,它先BuildHwndList的目的是为了告诉你它到底需要多大的缓冲区~~
|
能力值:
( LV9,RANK:610 )
|
-
-
10 楼
主要还是调试啊。。。
|
能力值:
( LV6,RANK:80 )
|
-
-
11 楼
换句话说,也只有你会这么乐意帮助别人了……嘿嘿
|
能力值:
( LV6,RANK:80 )
|
-
-
12 楼
我看你用的IDA哦,我的IDA不知道为啥很多符号解析不了……所以一看就晕菜了。然后用windbg直接u 一下,更晕了
|
能力值:
( LV9,RANK:610 )
|
-
-
13 楼
先调试找出现错误的地方,然后IDA分析,IDA可以加载pdb符号的啊。。。
|
能力值:
( LV6,RANK:80 )
|
-
-
14 楼
嗯嗯,自己工程生成的PDB是可用……但是我反 win32k.sys这个文件时,那些未导出符号全部用sub_xxxx 这种毫无意义的名称表示,不知道怎么能像windbg一样,那些函数名一类的,全部能解析出来……蛋疼啊~它说它会自动搜索符号文件,我咋就没看见它搜索了呢,依旧是sub_fuck
|
能力值:
( LV9,RANK:610 )
|
-
-
15 楼
最简单方法,把pdb和bin放在同一目录,然后IDA菜单里"Load Pdb",就OK了~~
|
能力值:
( LV6,RANK:80 )
|
-
-
16 楼
哦? 我试试看哈~
有了PDB,妈妈再也不用担心我反汇编了,哪里不对反哪里~so easy =.=
|
能力值:
( LV6,RANK:80 )
|
-
-
17 楼
教主,符号可以全部解析出来了, 我也发现你说的那个验证了,一个probeForWrite ,一个Win32UserProbeAddress对比,嗯嗯……这下IDA好看多了~
教我这么基本的技巧,肯定很郁闷吧……哈哈
|
能力值:
( LV9,RANK:610 )
|
-
-
18 楼
呵呵,有收获就好~
|
能力值:
( LV6,RANK:80 )
|
-
-
19 楼
教主,我刚调戏了一下,其实还有些问题…… hwndBuffer可以不是ring3的缓冲区,但是BufferSize必须是。返回0xC0000008的原因不止是这两个缓冲区的验证哦,还有一个 PtiFromThreadId这个函数,因为我是在PspCreateThread后获取的ThreaId,这时 PtiFromThreadId内部调用 PsGetThreadWin32Thread会失败……然后紧接着 PtiFromThreadId的跳转分支就会返回0xC0000008
|
能力值:
( LV9,RANK:610 )
|
-
-
20 楼
hwndBuffer必须是ring3的地址,ProbeForWrite是专门用来验证ring3地址的,自己看MSDN好了~~
如果不是,ProbeForWrite就会引起异常的,不信可以自已看ProbeForWrite的反汇编代码~~
|
能力值:
( LV6,RANK:80 )
|
-
-
21 楼
cmp eax,dword ptr [nt!MmUserProbeAddress (80559a54)]
了了~ 我一直没反过这个函数,一直以为它只会校验一下页属性,对齐一类的~
|
能力值:
( LV2,RANK:10 )
|
-
-
22 楼
教主,为什么我导入不了user32的符号?我用的windbg
|
|
|