如何获得其它进程创建的DDRAW指针 (0分)

  • 主题发起人 主题发起人 astros
  • 开始时间 开始时间
A

astros

Unregistered / Unconfirmed
GUEST, unregistred user!
如何获得其它进程创建的DDRAW指针
astros 2003.2.2 00:03
本人理论功底太薄,仅以个人经历和思考方式阐述发现获得其它
进程创建的DDRAW指针的过程,望各位大虾指教。
除夕之夜不想睡觉,但又无所事事,想看看IDirectDraw到底是如
何定义的,于是打开DDRAW.H,看到如下定义:
DECLARE_INTERFACE_( IDirectDraw, IUnknown )
那么这个"DECLARE_INTERFACE_"又是个什么东西?OBJBASE.H中有如下定义:
#define interface struct
#define DECLARE_INTERFACE_(iface, baseiface) interface DECLSPEC_NOVTABLE iface : public baseiface
而RPCNDR.H中又有如下定义:
#define DECLSPEC_NOVTABLE __declspec(novtable)
那么合起来,IDirectDraw的定义应该是:
struct __declspec(novtable) IDirectDraw : public IUnknown
就是说IDirectDraw是继承自IUnKnown的纯接口,这个也不新鲜,
早知道了。但是,"纯接口"?突然注意到这个词,虽然此前已经见过
无数遍了。那就是说,我们用DirectDrawCreate创建的DDRAW指针应
该是继承自这个接口的一个子类的实例的指针,那么这个实例又是如
何定义的呢?翻了无数资料也没找到答案。得,用跟踪程序跟踪进去
看看算了。
但是不知道为什么,在我的机器上,用TRW2000,一下BPX ddraw!DirectDrawCreate
就蓝屏、死机。不得已,编了如下的程序做拦截用:
bool TForm1::InitDirectDraw(HWND hwnd)
{
GetFileSize(NULL, NULL);
HRESULT result = DirectDrawCreate(NULL, &pDDraw, NULL);
if(result != DD_OK)
{
MessageBox(NULL, "DirectDrawCreate fail", "Error", MB_OK);
return false;
}
result = pDDraw->SetCooperativeLevel(hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
if(result != DD_OK)
{
pDDraw->Release();
pDDraw = NULL;
MessageBox(NULL, "SetCooperativeLevel fail", "Error", MB_OK);
return false;
}
前面的GetFileSize就是找了个不常用的函数做拦截用的。
用TRW2000载入程序,下命令:bpx getfilesize;x
中断了,按F12、F10,看到代码:(下面代码用Sourcer 7.0得到,
略加修改,比如kernal32!GetFileSize本来是jmp_GetFileSize,地址
也都不是016xx,是167:004016xx,更不可能有标号,但也相差不多,
意思一样就行)
PARAMETER_1 = 8 ;
EBP+8
PARAMETER_2 = 0Ch ;
EBP+0Ch
0167C 55 push EBP
0167D 8B EC mov EBP,ESP
0167F 51 push ECX
01680 6A 00 push dword ptr 0
01682 6A 00 push dword ptr 0
01684 E8 0004B31B call kernal32!GetFileSize
01689 6A 00 push dword ptr 0
0168B 68 000527F4 push 004527F4
01690 6A 00 push dword ptr 0
01692 E8 0004B26D call ddraw!DirectDrawCreate
01697 89 45 FC mov dword ptr [EBP-4],EAX
0169A 83 7D FC 00 cmp dword ptr [EBP-4],0
0169E 74 18 je short loc_0039
016A0 6A 00 push dword ptr 0
016A2 68 0004E39E push 4E39Eh
016A7 68 0004E388 push 4E388h
016AC 6A 00 push dword ptr 0
016AE E8 0004B8AB call user32!MessageBoxA
016B3 33 C0 xor EAX,EAX
016B5 59 pop ECX
016B6 5D pop EBP
016B7 C3 retn
016B8 loc_0039:
016B8 6A 11 push dword ptr 11h
016BA FF 75 0C push dword ptr [EBP+PARAMETER_2]
016BD 8B 15 000527F4 mov EDX,004527F4
016C3 52 push EDX
016C4 8B 0A mov ECX,[EDX]
016C6 FF 51 50 call dword ptr [ECX+50h]
016C9 89 45 FC mov dword ptr [EBP-4],EAX
016CC 83 7D FC 00 cmp dword ptr [EBP-4],0
016D0 74 2B je short loc_0040
016D2 6A 00 push dword ptr 0
016D4 68 0004E3BD push 4E3BDh
016D9 68 0004E3A4 push 4E3A4h
016DE 6A 00 push dword ptr 0
016E0 E8 0004B879 call user32!MessageBoxA
016E5 A1 000527F4 mov EAX,004527F4
没错,这就是我的代码,用BCB的DEBUG模式产生的代码真整齐啊!
下命令bd *,关掉所有断点,按F10单步执行,执行完call ddraw!DirectDrawCreate
之后,EAX=00000000,表示成功,那么现在pDDraw中保存的就应该是
那个"子类的实例的指针"了。由于call ddraw!DirectDrawCreate
前有push 004527F4,显然是把pDDraw的地址压入堆栈,那就看
看ds:004527F4里面是什么东西好了。d ds:004527F4,显示:
16F:004527F4 88 50 3F 84 ......
是了,还是个高端地址,看看去!d 843F5088,显示:
16F:843F5088 20 2E AF BA C4 FF 98 86-00 00 00 00 01 00 00 00
pDDraw就指向这么个东西?看起来象两个指针,后面都是0……联
想到后面pDDraw->SetCooperativeLevel的代码:
016BD 8B 15 000527F4 mov EDX,004527F4 ;这是pDDraw
016C3 52 push EDX
016C4 8B 0A mov ECX,[EDX] ;ECX=*((int*)pDDraw)
016C6 FF 51 50 call dword ptr [ECX+50h];(func*)ECX+50H是函数地址
那就是说pDDraw所指向的那块地址,第一个四字节值应该是vtable
的指针,里面有所有成员函数的地址,进去看看!d baaf2e20,显示:
BAAF2E20 23 CB AC BA BF 4D AC BA-07 B1 AD BA 06 86 AC BA
......
是一堆指针,应该没错了。那么第二个四字节值,看起来也象个
指针的是什么东西?下指令d 8698ffc4,显示:
16F:8698FFC4 00 00 00 00 1C F0 A8 86-00 00 00 00 00 00 00 00
这个86A8F01C看来也是个指针,指想哪里还不知道,不管它,先往下看:
16F:8698FFD4 01 00 00 00 9B 89 F7 FF-00 00 00 00 00 00 00 00
还是没什么特别的地方,只是这个FFF7899B的形式似乎挺熟悉,在哪里
见过……想起来了!98下的线程ID和进程ID不就是类似的形式吗?好,看看
去。考虑到线程太多,先看进程,下命令:PROC,显示:
Process pProcess ID Threads Context
-------- -------- -------- -------- --------
......
Project1 8197xxxx FFF7899B 2 C168xxxx
就是它!创建DDRAW指针的进程的ID!这说明第二个四字节值指向的是一
个和创建进程有关的信息结构。太爽了,至少这样解决了由DDRAW指针获得创
建它的进程的ID的问题。现在剩下的问题就是如何获得这个指针了。
考虑到COM接口都有AddRef和Release两个函数来进行引用计数,而我们创
建的这个pDDraw所指向的区域里只有两个指针吗?会不会有引用计数什么的?
所以,退出当前程序,启动DX7SDK所带的ddex4.exe这个DDRAW例程,顺便
也启动一下Flyfs.exe这个D3D例程,看看D3D在绘图上是不是真的基于DDRAW,
还是有什么区别。
好,在用TRW2000载入我的程序,设断点、跟踪执行完DirectDrawCreate之
后,pDDraw指向843DF618,于是d 843df618,显示:
16F:843DF618 20 2E AF BA 90 FB 3D 84-F8 B5 3D 84 01 00 00 00
16F:843DF628 00 00 00 00 00 00 00 00 ......
第一个四字节值是vtable的指针,第二个四字节值指向一个信息结构,……
???原来是0的第三个四字节值现在象是一个指针:843DB5F8,看看去:
16F:843DB5F8 20 2E AF BA 34 B5 3D 84-B8 A1 3D 84 06 00 00 00
16F:843DB608 00 00 00 00 00 00 00 00 ......
好类似的结构啊!会不会是另一个DDRAW的内容呢?因为现在系统中有3个
程序在使用DDRAW。前面的BAAF2E20和自己创建的DDRAW是一样的,显然是同一
个vtable,那么第二个843DB534会不会是一个信息结构呢?d 843DB534:
16F:843DB534 00 00 00 00 3C 92 4D 84-00 00 00 00 B7 04 00 00
16F:843DB544 0A 00 00 00 BD EE FF FF-00 00 00 00 00 00 00 00
16F:843DB554 B4 02 00 00 AE 0B 00 00-00 00 00 00 00 B8 3D 84
16F:843DB564 00 00 00 00 ......
还是太象了,看看同样偏移14H处的值:FFFFEEBD,用proc看看:
Process pProcess ID Threads Context
-------- -------- -------- -------- --------
......
Ddex4 8192620C FFFC9551 2 C1632130
Flyfs 8190F9C8 FFFFEEBD 2 C1630D60
......
可不是吗?正好是Flyfs.exe的进程ID,也就是说,843DB5F8开始的内存区
域应该是由Flyfs.exe创建的LPDIRECTDRAW所指向的区域。同样的,其第三个四
字节值指向的内容为:
16F:843DA1B8 00 2B AF BA D8 A0 3D 84-00 00 00 00 04 00 00 00
16F:843DA1C8 00 00 00 00 00 00 00 00 ......
这里的vtable值不一样了,正常,因为这一段应该是由Ddex4.exe创建的
LPDIRECTDRAW所指向的区域,而Ddex4.exe是使用DirectDrawCreateEx创建
LPDIRECTDRAW7的,IDirectDraw和IDirectDraw7的vtable当然应该不同。其信
息结构内容为:
16F:843DA0D8 00 00 00 00 3C 92 4D 84-00 00 00 00 37 04 02 00
16F:843DA0E8 04 00 00 00 51 95 FC FF-00 00 00 00 00 00 00 00
16F:843DA0F8 74 02 00 00 DE 0F 00 00-00 00 00 00 F8 8A 3D 84
16F:843DA108 00 00 00 00 ......
在同样的位置,也正好是Ddex4.exe的进程ID。
至此可以确认,pDDraw所指向的内存区域为链表结构,其第一个值为vtable
指针,第二个值为信息结构指针,第三个值为下一个结点的指针。信息结构的
偏移14H处保存了创建该DDRAW的进程的ID。
可是一个进程是可以多次调用DirectDrawCreate,创建多个DDRAW指针的,
这些指针之间是如何区分的呢?这时,想到我的程序也刚刚执行完DirectDrawCreate
而已,后面接着就是SetCooperativeLevel(hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN),
这里不是有一个窗口句柄吗?会不会这个句柄也被保存,用来区别连接到不同
窗口的DDRAW指针?幸好前面都抄下了不少数据,下命令hwnd,显示:
Window-Handle hQueue QOwner Class-Name Window-Procedure
......
0278(1) 4167 Ddex4 IME 170F:0000
0274(1) 4167 Ddex4 DDExample4 131F:07F4
......
008C(1) 1C37 Flyfs Tooltips 1737:669A
02B8(1) 1C37 Flyfs IME 170F:0000
02B4(1) 1C37 Flyfs Example 131F:0862
......
窗口句柄应该是0274和02B4,上去找找……哈哈,找到了!在信息结构偏
移20H处不就是窗口句柄吗?得意洋洋中……
至此,追踪DDRAW结构的行动告以段落。其实不是还有一些看起来象是指针
的数据吗?我追踪过,里面是很复杂的、相互关联的、包括象是指针、标志、
甚至函数地址的值,似乎是和DDRAW相关的数据,比如表面、调色板、剪裁区什
么的。但是我们已经获得了DDRAW的指针,又有现成的函数可以用,何必再费劲
分析那些乱七八糟的数据呢?做罢!
综合上面的分析,得到了一个小小的头文件MYDDRAW.H:
#ifndef MY_DDRAW_H
#define MY_DDRAW_H
#include <windows.h>
#pragma pack(push, 1) //要是BCB按缺省的8字节对齐,我的麻烦就大了
//DDraw信息内存结构
//DISP 14H处为进程ID
//DISP 20H处为窗口句柄
typedef struct
{
int reserved1;
int reserved2;
int reserved3;
int reserved4;
int reserved5;
int ProcessId;
int reserved6;
int reserved7;
HWND hWnd;
}MYDDRAWINFO, *PMYDDRAWINFO;
//DDraw内存结构
//DISP 00H处为函数表指针
//DISP 04H处为信息结构指针
//DISP 08H处为下一个DDraw结构指针
typedef struct MYDDRAW
{
void *pDDraw_Func_Table;
PMYDDRAWINFO pMyDDrawInfo;
MYDDRAW *pNext;
}*PMYDDRAW;
#pragma pack(pop)
#endif
正好以前做过一个使用钩子注入其它进程空间,弹出窗口的程序,一直苦
于无法获得该进程是否使用了DDRAW的信息,现在加进去:
COPYDATASTRUCT g_cdsData;
char g_pMsg[][64] = {
"Create DDraw failed",
"DDraw not found"
};
LPDIRECTDRAW pDDraw;
bool bDDraw = false;
HRESULT result = DirectDrawCreate(NULL, &amp;pDDraw, NULL);
if(result != DD_OK)
{//创建DDRAW失败,没想头了
g_cdsData.cbData = 64;
g_cdsData.lpData = g_pMsg[0];
SendMessage(hMyWnd, WM_COPYDATA, (int)hwnd, (long)(&amp;g_cdsData));
}
else
{//创建DDRAW成功
int pid = GetCurrentProcessId();//获取当前进程ID(因为是注入的,也就是其它进程ID了)
PMYDDRAW pMyDDraw = (PMYDDRAW)pDDraw;//转换成我的DDRAW结构,嘿嘿……
PMYDDRAWINFO pMyDDrawInfo;
while(pMyDDraw != NULL)
{//遍历链表
pMyDDrawInfo = pMyDDraw->pMyDDrawInfo;
if(pMyDDraw != (PMYDDRAW)pDDraw &amp;&amp;
pMyDDrawInfo->ProcessId == pid)
{//是这个被注入进程创建的,但又不是我刚才创建的DDRAW
char buf[512];
int l = sprintf(buf, "DDraw found with HWND:%08X", pMyDDrawInfo->hWnd);
g_cdsData.cbData = l + 1;
g_cdsData.lpData = buf;
//给我的窗口发回找到DDRAW的字符串
SendMessage(hMyWnd, WM_COPYDATA, (int)hwnd, (long)(&amp;g_cdsData));
bDDraw = true;
}
pMyDDraw = pMyDDraw->pNext;
}
if(!bDDraw)
{//没有找到,那就是它没创建DDRAW了
g_cdsData.cbData = 64;
g_cdsData.lpData = g_pMsg[1];
SendMessage(hMyWnd, WM_COPYDATA, (int)hwnd, (long)(&amp;g_cdsData));
}
pDDraw->Release();//我创建的DDRAW总是要释放的
pDDraw = NULL;
}
这里只是一个简单的示例,只要有了DDRW指针,还不是想干啥就干啥?嘿嘿……(奸笑中)
 
为什么是待答问题啊,你不是取到了吗?
但是你知道如何在别的directx上显示无闪烁的文字吗?
 
后退
顶部