首页
社区
课程
招聘
[原创]修复spy4win无法取ListView内容的BUG
2013-9-7 20:58 20479

[原创]修复spy4win无法取ListView内容的BUG

2013-9-7 20:58
20479
逆向发现之所以无法取得ListView的子项内容,是因为没有初始化ListView窗口的ListHeader句柄(此局部变量我们标记为hWndListHeader),就在对它调用SendMessage(hWndListHeader,HDM_GETITEMCOUNT,0,0)了,所以返回值始终为0,所以这个对话框始终是空的,

对其进行修复,也就是获取到hWndListHeader句柄,再执行原逻辑。

好了,成功了,现在能获取到子项内容了。

附修复代码:
// MyWork.cpp
#include "stdafx.h"
PVOID Ori_Call_SendMessageA_HDM_GETITEMCOUN_NoGetListHeaderHWND;
__declspec(naked) void Fix_Call_SendMessageA_HDM_GETITEMCOUN_NoGetListHeaderHWND()
{
        /*
        hListViewWnd              = ebx
        hWndListHeader            = dword ptr -3Ch
    ................................................................
        .text:0040857D                 push    0               ; lParam
        .text:0040857F                 push    0               ; wParam
        .text:00408581                 push    1200h           ; Msg
        .text:00408586                 mov     eax, [ebp+hWndListHeader]
        .text:00408589                 push    eax             ; hWnd
        .text:0040858A                 call    j_SendMessageA
        */
        __asm
        {
           push 0
           push 0
           push LVM_GETHEADER
           push ebx //hListViewWnd
           mov eax,[SendMessageA]
           call eax
           mov [ebp-3ch],eax //hWndListHeader
                   jmp Ori_Call_SendMessageA_HDM_GETITEMCOUN_NoGetListHeaderHWND;
        }
}
void BeginMyWork()
{
      PVOID pThatFunction=(0x0040857D-0x00400000)+(PBYTE)GetModuleHandle(NULL);
      HookFunction(pThatFunction,Fix_Call_SendMessageA_HDM_GETITEMCOUN_NoGetListHeaderHWND,&Ori_Call_SendMessageA_HDM_GETITEMCOUN_NoGetListHeaderHWND);
}

void EndMyWork()
{
     PVOID pThatFunction=(0x0040857D-0x00400000)+(PBYTE)GetModuleHandle(NULL);
     UnhookFunction(pThatFunction,&Ori_Call_SendMessageA_HDM_GETITEMCOUN_NoGetListHeaderHWND);
}

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"

#pragma comment(linker,"/EXPORT:DllMain=_DllMain@12")

void BeginMyWork();
void EndMyWork();
EXTERN_C BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
                {
                        //MessageBox(NULL,_T("加载成功"),_T("XXX.DLL"),MB_OK);
                BeginMyWork();
                }
                break;
        case DLL_THREAD_ATTACH:
                break;
        case DLL_THREAD_DETACH:
                break;
        case DLL_PROCESS_DETACH:
                {
                        EndMyWork();
                }
                break;
        }
        return TRUE;
}

编译为XXX.DLL,并对脱壳后Spy4Win.exe,用Lord PE的PE编辑器添加对XXX.DLL的依赖。Spy4Win.exe的脱壳,可以直接用Peid搞定。
HookFunction,及UnhookFunction是inline hook函数,可以在mhook等开源hook库中找到类似函数,本人恕不提供。
完美收官,YEAH。

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
点赞5
打赏
分享
最新回复 (22)
雪    币: 623
活跃值: (40)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
天高 2013-9-7 21:05
2
0
mark
雪    币: 3697
活跃值: (4086)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
sonyps 2013-9-7 21:22
3
0
本来是想联系作者修复的,可半年过去了,还是没猫洞,因为这个工具很强大,很常用,美中不足的就是这点一直不能用,所以只好做了个艰难的决定,自己来修正了。
附上测试中使用的本人编写制作的电子书程序成书《汇编语言》。
由CHM版转制生成。
上传的附件:
雪    币: 370
活跃值: (15)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
快雪时晴 4 2013-9-7 22:56
4
0
这该是精华啊,不错,spy4win好久不用了,刚去官网看了下
雪    币: 108
活跃值: (44)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
tuobaofeng 2013-9-8 01:43
5
0
不错,有时间看看
雪    币: 3697
活跃值: (4086)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
sonyps 2013-9-8 12:39
6
0
thanks.
雪    币: 260
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
guoyq 2014-5-8 22:18
7
0
win764 无法运行。。。
雪    币: 3697
活跃值: (4086)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
sonyps 2014-5-9 10:31
8
0
其他DLL也需要自己脱壳的 算了我还是提供个完整版本吧 也修复了WIN8下复制乱码的问题
(乱码问题原因,WIN8下调用SetClipboardData复制ANSI字符串到剪切板会有问题,改为复制UNICODE字符串就好了,实现在FACC.DLL,其他在WIN8下复制乱码的程序也可这样修正,简单的,你就加载(或注入)下FACC.DLL到你发现复制乱码的程序就好了)
上传的附件:
雪    币: 260
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
guoyq 2014-5-10 00:29
9
0
感谢!!!
雪    币: 1602
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
panti 2014-5-10 14:48
10
0
好,不错spy4win
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
skycny 2014-5-12 22:59
11
0
顶一个!!win7 64 完美运行!
雪    币: 3697
活跃值: (4086)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
sonyps 2014-5-14 20:20
12
0
修改日志:
20140514,修正官方原程序在64系统下,取64位进程的ListView控件内容时,会导致宿主进程崩溃的问题。错误原因是64位程序中ListView相关的消息结构体大小变了。只在WIN8.1 64位系统下测试了,WIN7的64位,由于本人未安装所以未测试。
上传的附件:
雪    币: 3697
活跃值: (4086)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
sonyps 2014-5-14 20:22
13
0
20140514修正代码:
#pragma pack(push,16)
typedef struct tagLVITEM64
{
        UINT mask;
        int iItem;
        int iSubItem;
        UINT state;
        UINT stateMask;
        PVOID64 pszText;
        int cchTextMax;
        int iImage;
        PVOID64 lParam;
#if (_WIN32_IE >= 0x0300)
        int iIndent;
#endif
#if (_WIN32_WINNT >= 0x0501)
        int iGroupId;
        UINT cColumns; // tile view columns
        PVOID64 puColumns;
#endif
#if _WIN32_WINNT >= 0x0600 // Will be unused downlevel, but sizeof(LVITEMA) must be equal to sizeof(LVITEMW)
        PVOID64 piColFmt;
        int iGroup; // readonly. only valid for owner data.
#endif
} LVITEM64, *LPLVITEM64;
typedef LVITEM64 LV_ITEM64;
typedef LPLVITEM64 LPLV_ITEM64;

typedef struct _HD_ITEM64
{
        UINT    mask;
        int     cxy;
        PVOID64 pszText;
        PVOID64 hbm;
        int     cchTextMax;
        int     fmt;
        PVOID64 lParam;
#if (_WIN32_IE >= 0x0300)
        int     iImage;        // index of bitmap in ImageList
        int     iOrder;        // where to draw this item
#endif
#if (_WIN32_IE >= 0x0500)
        UINT    type;           // [in] filter type (defined what pvFilter is a pointer to)
        PVOID64  pvFilter;       // [in] filter data see above
#endif
#if _WIN32_WINNT >= 0x0600
        UINT   state;
#endif
} HDITEM64, *LPHDITEM64;
#pragma pack(pop,16)

BOOL ProcessIs64Process(HANDLE hProcess)
{
        BOOL bRet=FALSE;
        if (hProcess)
        {
                static BOOL (WINAPI* _IsWow64Process)(__in  HANDLE hProcess,__out  PBOOL Wow64Process)=
                        (BOOL (__stdcall *)(HANDLE,PBOOL))GetProcAddress(GetModuleHandle(_T("kernel32.dll")),"IsWow64Process");
                BOOL bIsWow64;
                if (_IsWow64Process && _IsWow64Process(hProcess,&bIsWow64) && bIsWow64==FALSE)//64位进程
                {
                        bRet=TRUE;
                }
        }
        return bRet;
}

#define COPY_STRUCT_MEMBER(lpDstStruct,lpSrcStruct,Member) (lpDstStruct)->Member=(lpSrcStruct)->Member
#define COPY_STRUCT_MEMBER_EX(lpDstStruct,lpSrcStruct,Member,DstStructMemberType) (lpDstStruct)->Member=(DstStructMemberType)(lpSrcStruct)->Member

LRESULT (WINAPI* RealSendMessage)( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
LRESULT WINAPI MySendMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
        if (Msg==HDM_GETITEMA || Msg==HDM_GETITEMW)
        {
                HDITEM* phdi32=(HDITEM*)lParam;
                DWORD dwDstWindowProcessId;
                GetWindowThreadProcessId(hWnd,&dwDstWindowProcessId);
                CHANDLE hProcess=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION,FALSE,dwDstWindowProcessId);
                BOOL bTryToUseX64=ProcessIs64Process(hProcess);
                if (bTryToUseX64)
                {
                        HDITEM hdi32;
                        if (dwDstWindowProcessId!=GetCurrentProcessId())//不是本进程
                        {
                                SIZE_T ReadLen;
                                ReadProcessMemory(hProcess,phdi32,&hdi32,sizeof(hdi32),&ReadLen);
                                phdi32=&hdi32;
                                if (phdi32->mask &HDI_TEXT)
                                {
                                        WCHAR StrBuf[MAX_PATH];
                                        SIZE_T stGetStrLen=min(phdi32->cchTextMax,sizeof(StrBuf));
                                        ReadProcessMemory(hProcess,phdi32->pszText,StrBuf,stGetStrLen,&ReadLen);
                                        bTryToUseX64=(ReadLen==stGetStrLen);
                                }
                        }
                }
                if (bTryToUseX64)
                {
                        HDITEM64 hdi64={0};
                        LPHDITEM64 phdi64=&hdi64;
                        COPY_STRUCT_MEMBER(&hdi64,phdi32,mask);
                        COPY_STRUCT_MEMBER(&hdi64,phdi32,cxy);
                        COPY_STRUCT_MEMBER(&hdi64,phdi32,pszText);
                        COPY_STRUCT_MEMBER(&hdi64,phdi32,hbm);
                        COPY_STRUCT_MEMBER(&hdi64,phdi32,cchTextMax);
                        COPY_STRUCT_MEMBER(&hdi64,phdi32,fmt);
                        COPY_STRUCT_MEMBER_EX(&hdi64,phdi32,lParam,PVOID64);
                        COPY_STRUCT_MEMBER(&hdi64,phdi32,iImage);
                        COPY_STRUCT_MEMBER(&hdi64,phdi32,iOrder);
                        COPY_STRUCT_MEMBER(&hdi64,phdi32,type);
                        COPY_STRUCT_MEMBER(&hdi64,phdi32,pvFilter);
                        COPY_STRUCT_MEMBER(&hdi64,phdi32,state);
                        if (dwDstWindowProcessId!=GetCurrentProcessId())//不是本进程
                        {
                                PVOID pAllocBuf=VirtualAllocEx(hProcess,NULL,sizeof(hdi64),MEM_COMMIT,PAGE_READWRITE);
                                SIZE_T WriteLen;
                                WriteProcessMemory(hProcess,pAllocBuf,&hdi64,sizeof(hdi64),&WriteLen);
                                phdi64=(LPHDITEM64)pAllocBuf;
                        }
                        LRESULT lr=RealSendMessage(hWnd,Msg,wParam,(LPARAM)phdi64);
                        if (phdi64!=&hdi64)
                        {
                                SIZE_T ReadLen;
                                ReadProcessMemory(hProcess,phdi64,&hdi64,sizeof(hdi64),&ReadLen);
                                VirtualFreeEx(hProcess,phdi64,0,MEM_RELEASE);
                                phdi64=NULL;
                        }
                        COPY_STRUCT_MEMBER(phdi32,&hdi64,mask);
                        COPY_STRUCT_MEMBER(phdi32,&hdi64,cxy);
                        COPY_STRUCT_MEMBER_EX(phdi32,&hdi64,pszText,LPSTR);
                        COPY_STRUCT_MEMBER_EX(phdi32,&hdi64,hbm,HBITMAP);
                        COPY_STRUCT_MEMBER(phdi32,&hdi64,cchTextMax);
                        COPY_STRUCT_MEMBER(phdi32,&hdi64,fmt);
                        COPY_STRUCT_MEMBER_EX(phdi32,&hdi64,lParam,LPARAM);
                        COPY_STRUCT_MEMBER(phdi32,&hdi64,iImage);
                        COPY_STRUCT_MEMBER(phdi32,&hdi64,iOrder);
                        COPY_STRUCT_MEMBER(phdi32,&hdi64,type);
                        COPY_STRUCT_MEMBER_EX(phdi32,&hdi64,pvFilter,void*);
                        COPY_STRUCT_MEMBER(phdi32,&hdi64,state);
                        return lr;
                }

        }
        else if (Msg==LVM_GETITEMTEXTA || Msg==LVM_GETITEMTEXTW)
        {
                LVITEM* pitem32=(LVITEM*)lParam;
                DWORD dwDstWindowProcessId;
                GetWindowThreadProcessId(hWnd,&dwDstWindowProcessId);
                CHANDLE hProcess=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION,FALSE,dwDstWindowProcessId);
                BOOL bTryToUseX64=ProcessIs64Process(hProcess);
                if (bTryToUseX64)
                {
                        if (dwDstWindowProcessId!=GetCurrentProcessId())//不是本进程
                        {
                                LVITEM item32;
                                SIZE_T ReadLen;
                                ReadProcessMemory(hProcess,pitem32,&item32,sizeof(item32),&ReadLen);
                                pitem32=&item32;
                                if (pitem32->mask &LVIF_TEXT)
                                {
                                        WCHAR StrBuf[MAX_PATH];
                                        SIZE_T stGetStrLen=min(pitem32->cchTextMax,sizeof(StrBuf));
                                        ReadProcessMemory(hProcess,pitem32->pszText,StrBuf,stGetStrLen,&ReadLen);
                                        bTryToUseX64=(ReadLen==stGetStrLen);
                                }
                        }
                }
                if(bTryToUseX64)
                {
                        LVITEM64 item64={0};
                        LPLVITEM64 pitem64=&item64;
                        COPY_STRUCT_MEMBER(&item64,pitem32,mask);
                        COPY_STRUCT_MEMBER(&item64,pitem32,iItem);
                        COPY_STRUCT_MEMBER(&item64,pitem32,iSubItem);
                        COPY_STRUCT_MEMBER(&item64,pitem32,state);
                        COPY_STRUCT_MEMBER(&item64,pitem32,stateMask);
                        COPY_STRUCT_MEMBER(&item64,pitem32,pszText);
                        COPY_STRUCT_MEMBER(&item64,pitem32,cchTextMax);
                        COPY_STRUCT_MEMBER(&item64,pitem32,iImage);
                        COPY_STRUCT_MEMBER_EX(&item64,pitem32,lParam,PVOID64);
                        COPY_STRUCT_MEMBER(&item64,pitem32,iIndent);
                        COPY_STRUCT_MEMBER(&item64,pitem32,iGroupId);
                        COPY_STRUCT_MEMBER(&item64,pitem32,cColumns);
                        COPY_STRUCT_MEMBER(&item64,pitem32,puColumns);
                        COPY_STRUCT_MEMBER(&item64,pitem32,piColFmt);
                        COPY_STRUCT_MEMBER(&item64,pitem32,iGroup);
                        if (dwDstWindowProcessId!=GetCurrentProcessId())//不是本进程
                        {
                                PVOID pAllocBuf=VirtualAllocEx(hProcess,NULL,sizeof(item64),MEM_COMMIT,PAGE_READWRITE);
                                SIZE_T WriteLen;
                                WriteProcessMemory(hProcess,pAllocBuf,&item64,sizeof(item64),&WriteLen);
                                pitem64=(LPLVITEM64)pAllocBuf;
                        }
                        LRESULT lr=RealSendMessage(hWnd,Msg,wParam,(LPARAM)pitem64);
                        if (pitem64!=&item64)
                        {
                                SIZE_T ReadLen;
                                ReadProcessMemory(hProcess,pitem64,&item64,sizeof(item64),&ReadLen);
                                VirtualFreeEx(hProcess,pitem64,0,MEM_RELEASE);
                                pitem64=NULL;
                        }
                        COPY_STRUCT_MEMBER(pitem32,&item64,mask);
                        COPY_STRUCT_MEMBER(pitem32,&item64,iItem);
                        COPY_STRUCT_MEMBER(pitem32,&item64,iSubItem);
                        COPY_STRUCT_MEMBER(pitem32,&item64,state);
                        COPY_STRUCT_MEMBER(pitem32,&item64,stateMask);
                        COPY_STRUCT_MEMBER_EX(pitem32,&item64,pszText,LPSTR);
                        COPY_STRUCT_MEMBER(pitem32,&item64,cchTextMax);
                        COPY_STRUCT_MEMBER(pitem32,&item64,iImage);
                        COPY_STRUCT_MEMBER_EX(pitem32,&item64,lParam,LPARAM);
                        COPY_STRUCT_MEMBER(pitem32,&item64,iIndent);
                        COPY_STRUCT_MEMBER(pitem32,&item64,iGroupId);
                        COPY_STRUCT_MEMBER(pitem32,&item64,cColumns);
                        COPY_STRUCT_MEMBER_EX(pitem32,&item64,puColumns,PUINT);
                        COPY_STRUCT_MEMBER_EX(pitem32,&item64,piColFmt,int*);
                        COPY_STRUCT_MEMBER(pitem32,&item64,iGroup);
                        return lr;
                }
        }
        return RealSendMessage(hWnd,Msg,wParam,lParam);
}
雪    币: 204
活跃值: (69)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
junlinsky 2014-5-14 23:38
14
0
一直很佩服这样的文章
雪    币: 189
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
RinceLeung 2017-5-25 14:29
15
0
好強大,  跟樓主學習了
雪    币: 52
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lizx 2018-4-29 18:16
16
0
原程序360不报毒,为什么楼主之后打包的S4wHook.dll报毒TR.ATRAPS.Gen?
雪    币: 3697
活跃值: (4086)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
sonyps 2018-4-29 22:04
17
0
不晓得  差别就是脱了壳  不放心就不要用吧
雪    币: 205
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yangjiyou 2018-5-6 16:45
18
0
很好的东西,可惜就是在通达信委托的程序TDXW.exe中不能取到其中涉及到的所有SysListView32,标题头能取到,内容不能取到。
雪    币: 205
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yangjiyou 2018-5-6 16:47
19
0
ListView的项目数:  7
-------------------------
委托日期          委托编号      证券代码      证券名称        买卖标志        委托价格      委托数量      成交价格      成交数量      撤单数量      报价方式      结果说明        冻结资金             
--------------------------------------------------------------------------------------------------------------------------------------------------------
                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                               
雪    币: 205
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yangjiyou 2018-5-6 16:58
20
0
哦,刚才说满了,有一个SysListView32内容可以读出,其他的SysListView32不行
雪    币: 3697
活跃值: (4086)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
sonyps 2018-5-6 21:30
21
0
可能他是自绘造成的吧
雪    币: 196
活跃值: (37)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
落荒 2022-2-21 11:16
22
0

感谢楼主出手修正!可惜Spy4Win似乎还是存在一些问题,一个是获取文本时仍然存在乱码的可能性(大体原因应该是由于Spy4Win都是使用ANSI版的API,对于Unicode字串支持不好),另一个是ListView有时候获取列不全(以64位Win10的任务管理器为例)。


最后还是自己用Delphi写了一个标准ListView专用的文本提取器(上面提到的第一个问题已验证Delphi 7编译版也存在同样情况,但换成Embarcadero编译之后就一切正常,所以基本上可以归结为Unicode支持问题),ListView获取不全的情况也没有发生,应该是Spy4Win本身还有Bug要补一下吧。楼主有空的话可以试试能不能再完善一下,但也不强求,哈哈。


最后于 2022-2-21 11:24 被落荒编辑 ,原因:
上传的附件:
雪    币: 3697
活跃值: (4086)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
sonyps 2023-2-23 15:26
23
0
落荒 感谢楼主出手修正!可惜Spy4Win似乎还是存在一些问题,一个是获取文本时仍然存在乱码的可能性(大体原因应该是由于Spy4Win都是使用ANSI版的API,对于Unicode字串支持不好),另一个是L ...

乱码问题,多年前修复过的,只是没发布。最新版本修复了在高分屏上的使用问题。

上传的附件:
游客
登录 | 注册 方可回帖
返回