原理QTP,编写属于自己的控件控制插件

上一篇 / 下一篇  2009-05-07 17:50:25 / 个人分类:体会

 很久没有来51testing了,忙死,看到陈旧的BLOG,就随便写点文章冲数拉,虽然拙劣,但始终是我的原著嘛,我就自己打上水印了,拒绝盗版哦,如有错误或者建议,还是可以通过mythxhg@163.com与我联系.

"u-vB8lQ3Jl0

51Testing软件测试网4c#s9w`W Z1V%Nk

 在QTP应付一些不识别对象或者QTP无法达到自己的期望的时候,许多人都感到无可奈何,也尽量用一些小技巧小方法左缝右补,但始终是显得力不从心,无法达到满意的自动化效果,我也层总结过自己应付这类型问题的方法,下面我就详细讲解一种正面解决问题的方法,也就是编写自己的控件控制插件51Testing软件测试网0@'uvTS{

 在此之前,先简单讲解一下有关进程内控制以及跨进程控制的基本知识。51Testing软件测试网U*TR&G(ykw:d

 1.进程内控制,这个可以说会写代码的人都会,因为他们编写的代码就是控制其控件按其自己想要的方式运行的过程。51Testing软件测试网0C I1]Z+PbE5n

       例如51Testing软件测试网R Z#@,f E

  在进程内部知道自己的句柄m_hClient后可以这样用

s:Pi[QbYlm_%VV0

  CListCtrl* cw = (CListCtrl*)( CWnd::FromHandle(m_hClient) );

F'Gt@ Jsp3^0

  CString sss = cw->GetItemText(0,0);

[/r Ci1y0

       2.再说说跨进程控制,跨进程控制中,什么信息对我们有用?需要跨进程控制某个窗体,对我们有用的当然是窗口句柄啦。QTP对一些不识别的对象都识别为WINOBJECT.对吧,但QTP虽然不识别,但还是可以做最基本的CLick,Move,获取位置,句柄等等。为什么呢?因为正是使用了句柄。

@ t:R%W,]M,m O-D0

 说到这里可能有很多人想,喔,原来这么简单,那我用QTP取到句柄之后就随便写控制代码啦。真的这么简单吗?51testing上有个例子是用句柄把窗口隐藏,没错,这个直接用ShowWindow(Handle,SW_HIDE)就可以了。的确,直接使用句柄就可以实现部分控制了,但是直接使用所能控制的程度有限,因为你能直接控制时因为对方认为这些操作都是合法的,有权限的,CListCtrl继承于CWnd,而CWnd的大部分方法对外是开放的,这是废话,要不你也操作了不窗口啦,所以CWnd的一些对外开放的操作同样可以用到CListCtrl上,正因如此我们才可以使用这些操作,但是如果你用上面得方法CListCtrl* cw = (CListCtrl*)( CWnd::FromHandle(m_hClient) );CString sss = cw->GetItemText(0,0),我敢保证你取不到任何值,甚至你的程序会崩溃。为什么呢?因为这些操作是CListCtrl内部使用的,它没有对系统公开,要不然WINDOWS就乱套了,随便写点东西就把你的程序改了。51Testing软件测试网zz v$W4RM

 &说了那么多那么乱,其实就说明一个,窗体对你开放的操作你是可以直接用它的句柄进行操作就可以了,但对哪些受保护的操作我们是没有权限取执行的,因为他们位于不同的进程空间,权限是其一,不同进程控件的内存寻址也是导致你无法直接控制的原因。所以,要取得权限,你的操作必须是在对方进程内部使用。51Testing软件测试网5r"`0@-J1|+Y#e&P wJ

 好,那么怎样取得权限?注入。。对,远程注入,注入的方法很多,但现在我讲解其中一种,注入DLL(DLL注入也有几种方法,1是钩子,2是远程调用,下面讲解的是第2种方法,钩子是消息驱动的,各位也可以试试,相对来说钩子更简单,但受限于消息,我更喜欢远程调用)。51Testing软件测试网5w$l3}5VD7?8wT

 理一下思路,现在我们要把51Testing软件测试网,N&F.N7U$@e#m_v

  CListCtrl* cw = (CListCtrl*)( CWnd::FromHandle(m_hClient) );51Testing软件测试网_N'PTKG

  CString sss = cw->GetItemText(0,0);51Testing软件测试网6IqB"KeZ

 这些代码放到DLL内部注入到其他进程中。

o9u0t]:xJCW8bL0

 代码如下:

6LA}mkR:~_+^0

 CString szApp = "TestApp.exe";

3\2\U.O s |;js s0

 CString szDll = "D:\\AtmRobot\\Src\\Hacker\\Debug\\Hacker.dll";

6f:L_7uo0x-]\,E0

 DWORD m_dwProcessId = 0;

FGx gr9r,HV0

 DWORD  hLibModule;  //已加载的DLL的基地址(HMODULE);

)kI@;X3Mn%K!Z_*J0

 PROCESSENTRY32 pe;51Testing软件测试网sC;A+j @%c

 HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

mF-J-d:ro3h F0

 Process32First(hSnapshot, &pe);51Testing软件测试网2zR"}){*s!B

 do{ 51Testing软件测试网?-l g!V3mIb

  if(strcmp(pe.szExeFile,szApp) == 0      ) 51Testing软件测试网x$v7G'J*Wb Y(|`

  { 

^,L ~\4Eq:s0

   m_dwProcessId =pe.th32ProcessID;51Testing软件测试网M#un kQ V

   break; 51Testing软件测试网g-W Q6j#RB4M

  }51Testing软件测试网1blL e-c

 }while (Process32Next(hSnapshot, &pe));51Testing软件测试网 Iw`&e2mg9U-ik)L

 CloseHandle(hSnapshot);

e6R Y:oA0M0

 LPSTR lpszRemoteFile,lpszLibName;51Testing软件测试网{8^ _KV

 lpszLibName = (LPSTR)(LPCTSTR)szDll;51Testing软件测试网:R7vt@4v/H

 

W tC(c1Mi(N&n0

 HANDLE hProcess;51Testing软件测试网nYm'A"YN9k,K/}U

 hProcess = OpenProcess(PROCESS_CREATE_THREAD 

Y6K+I&`j0

  | PROCESS_VM_OPERATION

*w ]2m_@:v0

  | PROCESS_VM_WRITE,51Testing软件测试网cv"vt8A$o

  FALSE,51Testing软件测试网qq;F-rnQ

  m_dwProcessId);51Testing软件测试网jA i0z U&U

 lpszRemoteFile = (LPSTR)VirtualAllocEx51Testing软件测试网B/cW\(b f)uk&Ra

  (hProcess, NULL, sizeof(CHAR) * strlen(lpszLibName) + 1, MEM_COMMIT, PAGE_READWRITE);51Testing软件测试网5{-u)H#C7w7G

 WriteProcessMemory(hProcess, lpszRemoteFile, (PVOID)lpszLibName, sizeof(CHAR) * strlen(lpszLibName) + 1, NULL);51Testing软件测试网3A m,s?u3Y4TMn4F

 

|ye*`%R0

 PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(

M]W0Eo0

  GetModuleHandle("Kernel32.dll"),"LoadLibraryA");

rY|n7M fZ:j.d0

 51Testing软件测试网Ojxly

 HANDLE hTread = CreateRemoteThread(hProcess, 51Testing软件测试网Ed/L*R4A a A

  NULL, 51Testing软件测试网L$SRCk)N

  0, 

+JxCZ f G8w"J0

  pfnThreadRtn, 51Testing软件测试网E7y y pw

  lpszRemoteFile, 51Testing软件测试网 e zXU/[P1H

  0, 51Testing软件测试网4n `/?:S)}!w2s/S*O

  NULL);

"h^-W2knim.e0

 WaitForSingleObject(hTread, INFINITE);

`{8B1KkhU7d%F5Af0

 ::GetExitCodeThread( hTread, &hLibModule );

sUQ)bQ$n1\0

 VirtualFreeEx(hProcess, lpszRemoteFile, 0, MEM_RELEASE);

.C9XtMB:Ns_0

 CloseHandle(hTread);51Testing软件测试网qFFS+N R-v,C

 CloseHandle(hProcess);51Testing软件测试网;as9B x Bi3L:J^+Xe q

       

%NOKf8k6H8Q+q0

       这样我们就通过进程名以及DLL的本地路径就实现了DLL的注入。

-nAO"^9@*Lw0

       注入了,但是问题跨进程的调用可不像本地程序,你是不能直接使用对方的变量或者函数的,理由上面说过了。那么如何通讯?通讯方法也很多,不过由于位于不同的进程空间,处理起来如果不够熟练是很容易出错的,我下面介绍一种比较投机的小方法,可以方便通讯。

,bN O s+Uz0

 注入的DLL我们使用MFC规则DLL,并且编译为静态,避免缺少什么而崩溃。

c;i~+N:h/S)vV0

 默认建立完成一个MFCC规则DLL后,不需要做其他东西,直接为其添加一个MFC窗口Dialog类CMyHackerDlg。

0Db%O1u7nSyZl0

 然后我们添加一个消息响应函数

yS%I7j:M5PI+z0

 先定义一个消息宏  #define WM_SETHWND    WM_USER+2051Testing软件测试网9uU ?2?+c

 再定义一个消息响应函数  ON_MESSAGE(WM_SETHWND , OnSetHwnd)

$c;jH*n4~6N0

 函数体:

1`\)I7o9e0[+t0

  void CMyHackerDlg::OnSetHwnd(WPARAM w,LPARAM l)

[$b(`9qc0

  {51Testing软件测试网.u/t5s#Yo9Z

   m_hClient = (HWND)w;51Testing软件测试网 _U/]:x Z!W+C*~

   CListCtrl* cw = (CListCtrl*)( CWnd::FromHandle(m_hClient) );51Testing软件测试网F(T9{3fwY'Q

   CString sss = cw->GetItemText(0,0);

N k:dZ]IC0

   AfxMessageBox(sss);

|-Ktg t y!Q7M0

  }51Testing软件测试网j$t1yv8z4u`

 为什么我要为这个DLL添加消息响应函数呢?不是为别的,正是为了方便通讯,通过消息,我们可以随意的调用我们自己想调用的代码.51Testing软件测试网;Qd)@ F$nW2G|$EJ

 为DLL添加了窗口类之后还需要做一些事情,把窗体创建起来,但是注意,不要模态的创建,这样会阻塞程序,所以我们需要动态创建。但是还有一个比较严重的问题,这样动态创建的窗体时不是正常运行的,为什么?因为没有消息循环。。DLL本身是不会提供这个的,所以我们要起一个线程,在线程里创建窗体并提供消息循环。代码如下:

!Qd&](zZ(E/n}T0

CMyHackerDlg g_oDlg;51Testing软件测试网Y\ R-MI'{5NAQ

HANDLE hThread1;51Testing软件测试网ub6j0KA:I

bool bflag;

kqo t }I'~9E0

DWORD WINAPI SDKThread(LPVOID lpParameter)

1N"k\ZUU*p0

{

V)|d2No8j6kr'W0

 g_oDlg.Create(IDD_HACKER_DIALOG);51Testing软件测试网$y[p*?S.aq

 g_oDlg.SetWindowPos(&CWnd::wndNoTopMost,0,0,0,0,SWP_NOSIZE);51Testing软件测试网k `Sw2\

 g_oDlg.ShowWindow(SW_SHOW);51Testing软件测试网.}3Tkl.`U

 bflag = false;51Testing软件测试网)Z,yq v c0p]|v4W9A

 MSG msg;

W$Xd~[9B0

 while(GetMessage(&msg, NULL, 0, 0) != 0)

&z{`}H!|S0

 {51Testing软件测试网)UJ o.Zg]!sN,[

  TranslateMessage(&msg);51Testing软件测试网(NSNzW'|

         DispatchMessage(&msg); 

ko3W_*u!O'Y&{8_G0

  if (bflag)

nw(q;ar*IH l8y _0

  {51Testing软件测试网,o4h6]Z7NvU

   AfxMessageBox("QUIT");51Testing软件测试网6eM.B6t&d_8QUq

   break;

xY R)` tjj0

  }51Testing软件测试网t^z"a7AMo)c*l

 }51Testing软件测试网;j7J8__(u0E4q@:B

 return 0;51Testing软件测试网3^u$Nr,E,i4u

}

q-hrPN7g0

51Testing软件测试网m*pAK\`m7qt

BEGIN_MESSAGE_MAP(CHackerApp, CWinApp)51Testing软件测试网,a/a#o:^,Z,I

 //{{AFX_MSG_MAP(CHackerApp)

2Rp-B"M|4lO'O&S0

  // NOTE - the ClassWizard will add and remove mapping macros here.51Testing软件测试网#J? Xpe+B9T

  //    DO NOT EDIT what you see in these blocks of generated code!

\+W1zZ|6m0

 //}}AFX_MSG_MAP

)sDS,R }~0

END_MESSAGE_MAP()

~*_ho'S2} {0

Z9v.V:c~,U-P0

/////////////////////////////////////////////////////////////////////////////51Testing软件测试网&T,L7z/\+pB

// CHackerApp construction51Testing软件测试网.y2`t-E9r j}"W`

51Testing软件测试网"at?5i d7Z"p

CHackerApp::CHackerApp()

M@s7y{0r2C0

{51Testing软件测试网:hbWQW

 // TODO: add construction code here,51Testing软件测试网 Q'w g;FN|6z K5c$n

 // Place all significant initialization in InitInstance

5ZR#B~gu/e~0

 DWORD dwThreadID;

E)q6JNN0

 hThread1=::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)SDKThread,/*(LPVOID)m_sys_param*/this,0,&dwThreadID);

4E}%J$l u/?F#`m0

}

/j8@ RSih.~5`${0

_O ^9O'dah o s)c0

CHackerApp::~CHackerApp()51Testing软件测试网-Tvb,I1^ };[Wf

{

JSN:Ol v? t9P0

 CloseHandle(hThread1);51Testing软件测试网7~`;MoeJ7c}Z

}

B}2S)~X#Q0

51Testing软件测试网F8ql|!W

 这样我们试试看结果,是不是很好玩?把DLL注入之后就可以发现出现了我们建立的窗体,然后我们通过QTP获取到得要控制的控件的句柄通过Sendmessage传递给我们窗体的消息响应行数处理,做任何想要做的事情了。如果你不想显示这个DLL的窗体,那么你把g_oDlg.ShowWindow(SW_SHOW);改成g_oDlg.ShowWindow(SW_HIDE);就可以了。

:i8kcq5I\XQ _q0

 我们的DLL完成任务之后就是关闭窗体,释放DLL的工作了。

w.i!S o8Rq*m0

 HANDLE hProcess;51Testing软件测试网b!h Kb\{)I~N

 hProcess = OpenProcess(PROCESS_CREATE_THREAD 

b6E/Y \iH(P8l#Y0

  | PROCESS_VM_OPERATION

4n yJm-_wL8\-B0

  | PROCESS_VM_WRITE,51Testing软件测试网1C S%Kp[@

  FALSE,51Testing软件测试网b!sv"B/s

  m_dwProcessId);51Testing软件测试网a9u$d`6M1xe

 PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(

U&~([ Ssw0

  GetModuleHandle("Kernel32.dll"),"FreeLibrary");

s4@"V1jY/gc2Q0

 HANDLE hTread = CreateRemoteThread(hProcess, 51Testing软件测试网 RG E/n']-C1l

  NULL, 

-S!e&~df'v8eBD0

  0, 51Testing软件测试网5@4~l!t?%LFM5}&G

  pfnThreadRtn, 

ADy.WpL1r D T0

  (void*)hLibModule,

*^E$~a.o|o0

  0, 

zDX(A*U0

  NULL);51Testing软件测试网 vm9ly'z#~:i

 ::WaitForSingleObject( hTread, INFINITE );51Testing软件测试网^)JF%z b`rOX\L$w

 ::CloseHandle( hTread );51Testing软件测试网\ x0EE\ ]8C ];R

 51Testing软件测试网fh#Qz'WZ1b&sW~

 到这里,我们就可以编写自己的控制代码里,(我猜QTP其实也是用同样的原来来实现的,因为我们用QTP测试的时候发现被测对象挂上了一个QTP程序的DLL),对吧,QTP现在看来是不是觉得仅仅是一个辅助工具了?事实上QTP仅仅就是一个工具,能把它用到什么程度,如何用QTP配合自己完成自动化工作,这个完全视乎你自身,如果你现在还是整天沉醉在如何使用QTP的函数库,我想是时候改变一下了。

.`5FL\9o bd0

y8J5d/A*{4y{0A%[0

TAG: DLL QTP 控制 插件

 

评分:0

我来说两句

日历

« 2024-01-20  
 123456
78910111213
14151617181920
21222324252627
28293031   

数据统计

  • 访问量: 31297
  • 日志数: 33
  • 图片数: 3
  • 文件数: 8
  • 建立时间: 2007-10-10
  • 更新时间: 2011-06-28

RSS订阅

Open Toolbar