您的位置:首页精文荟萃破解文章 → smartsearch保存功能之添加

smartsearch保存功能之添加

时间:2004/10/15 0:58:00来源:本站整理作者:蓝点我要评论(0)

 刚吐血完成diype那个网聪,现在又来吐血写教程,写完我就要去医院输血了,大家记得免费捐点:)  
文章题目:我的diype历程之一(smartsearch保存功能之添加)  
破解工具:太多。。。。  
破解目的:正在思考:)  

diype=Dancing In Your Program Empire(最新解释:)  

首先感谢pll621大哥为我们提供了6篇高质量的diype教程,还有许多前辈们为此作的研究,都给了我动力和帮助。diype的确是一项很累人的工作,其间upfeed对我的指点功不可没,我谨以此篇文章献给所有帮助我的朋友们,当然也是对我劳动的总结,同时我也想以此作为给初学者的教程(但是初学者的概念很难界定,我也是初学者,很多人还称自己是菜鸟,虽然对我来说他们已经是肉鸟:),所以如果你觉得还看不懂那么一定是我文笔太差,而不是你水平不够)。  

言归正传,让我们磨刀霍霍向网聪(希望原作者不要看到这篇文章:)  

写在前面:这里我希望你已经具备了win32asm的基本知识,如果没有可以查看一下win32asm基础教程。  
          其次你应该对winapi有初步的了解,如果没有至少你应该有这个winapi帮助手册,这两样看雪里都有!  

网聪的这款软件注册机及破解方法我以在以前的文章中说过,但是在注册成功后,最为关键的保存功能居然仍然没有,用dede反编译后发现那里只有一个用来显示什么"付费用户才能用此项功能"的nag而没有其他的代码,说明作者没有在这个网络下载版里提供这项功能,这有两种可能,1。作者根本没在这个版里写代码,2。他写了但是只有付费后才会提供一个补丁修改为指向这段代码。(事实上在我修改程序时发现的确有一些代码没有使用,可能他有写在里面,但是由于我已经在自己添加了,而且去寻找正确的代码入口也很困难,所以就没在细究)下面我们来分析要手动添加代码所要做的工作:  

1。回忆一下传统的保存功能都是怎样的过程,首先在点击保存后,要打开一个对话框要你输入你要保存的文件名,这个可以用api里getsavefilename其次在你输入名称后点确定,会创建一个新文件,或者覆盖原来的文件,这个用createfile来实现,当然createfile只是创建文件,你还要将信息保存进去,所以还要用writefile来实现,最后别忘了关闭文件closehandle。这就是保存文件所要做的,当然还有内存的操作,这个我后面再说。  

2。接下来看看我们要把什么保存进去,当然是我们搜索到的电邮地址,可以通过dede很清楚地找到存放地址的控件是叫做stringgrid的东西,现在我们还不清楚他是怎么保存的,也就是说究竟以何种数据结构保存搜索到的结果。这是我们需要分析的。  

3。我们要找到程序的空余部分,好添加代码,如果你觉得不够,还要自己加一个section,或者在原来的section上增加一些。这个工作很好做,用topo就可以:)(peter老大教的)  

好我们明确了目标,就可以开始了,从最简单的开始,3最简单:),我们找找程序的空余部分,我用的是4a9426开始的空间,我开始以为不够,所以又添加了一个section,从4d4000开始。(好像差不多刚好,没有仔细的统计,反正增加几百字节也无所谓,重要的是能把东西做出来:)  

完成了一步很开心吧?没有。。。太简单了?你还要怎样:)好进入第2,分析一下stringgrid的运作方式,开始我很迷惑,因为跟踪后发现他存放的空间不连续,我以为那不是正确的地址,还有一块连续的地方存放,百思不解后在upfeed的提醒下,我自己用delphi写了一段stringgrid的代码,发现我的想法是对的,只不过因为这个程序用的是多线程,所以每个线程都拥有一些结果,线程内是连续的,线程之间就是不连续的分配起始地址了,看来有时候还要自己写代码来分析,要不会被迷惑的,来看看它是怎么存放的:  

004A12EA  ||MOV EAX,DWORD PTR DS:[4ACC14]  
004A12EF  ||PUSH EAX                        ; /Arg1 => 00BB3DB4 ASCII "sales@eyou.com"  
004A12F0  ||MOV ECX,DWORD PTR DS:[4AD0C0]    ; |  
004A12F6  ||XOR EDX,EDX                      ; |  
004A12F8  ||MOV EAX,DWORD PTR DS:[EBX+2F8]  ; |  
004A12FE  ||CALL smartsea.00468568          ; \smartsea.00468568  //这个就是设置stringgrid元素值的,跟进去看看  
004A1303  ||INC DWORD PTR DS:[4AD0C0]  

00468568  /$>PUSH EBP  
00468569  |.>MOV EBP,ESP  
0046856B  |.>PUSH ECX  
0046856C  |.>PUSH EBX  
0046856D  |.>PUSH ESI  
0046856E  |.>PUSH EDI  
0046856F  |.>MOV DWORD PTR SS:[EBP-4],ECX  //当你每次运行到这里就会发现在[ebp+8]这个堆栈里存放着你想要的搜索到的邮件地址  
00468572  |.>MOV ESI,EDX                      虽然它不是一个接一个的规律变化,原因刚才我讲了,但是我们可以把这些指针保存起来呀:)  
00468574  |.>MOV EBX,EAX  
00468576  |.>MOV EDX,DWORD PTR SS:[EBP-4]  
00468579  |.>MOV EAX,EBX  
0046857B  |.>CALL smartsea.004684A4  
00468580  |.>MOV ECX,DWORD PTR SS:[EBP+8]  
00468583  |.>MOV EDX,ESI  
00468585  |.>MOV EDI,DWORD PTR DS:[EAX]  
00468587  |.>CALL DWORD PTR DS:[EDI+20]  
0046858A  |.>MOV CL,1  
0046858C  |.>MOV EDX,ESI  
0046858E  |.>MOV EAX,EBX  
00468590  |.>CALL smartsea.00468440  
00468595  |.>XOR ECX,ECX  
00468597  |.>MOV EDX,DWORD PTR SS:[EBP-4]  
0046859A  |.>MOV EAX,EBX  
0046859C  |.>CALL smartsea.00468440  
004685A1  |.>MOV ECX,DWORD PTR SS:[EBP-4]  
004685A4  |.>MOV EDX,ESI  
004685A6  |.>MOV EAX,EBX  
004685A8  |.>CALL smartsea.004683F4  
004685AD  |.>POP EDI  
004685AE  |.>POP ESI  
004685AF  |.>POP EBX  
004685B0  |.>POP ECX  
004685B1  |.>POP EBP  
004685B2  \.>RETN 4  


现在我们来做这个保存,我原先的设想把这些指针保存到我开辟的新的section里,这样不用做内存操作,省去一些代码,后来想了一想,如果以我们搜索到1000个地址为例,因为指针是dword,也就是说需要4000字节来存放这些指针,晕倒,所以看来不能偷懒,还是老老实实开一块内存来吧。  

对内存的操作我这样实现,首先globalalloc一块内存,然后globallock,这样我们就可以保存进去,最后要记得globalunlock,globalfree。(不懂就去查前面两个手册)那么什么时候申请这块内存呢?我是在formcreate的时候做的,你可以在其他时候,只要保证你后面要保存指针的时候有内存用。  

0049B134  .>PUSH EBP                            //formcreate开始  
0049B135  .>MOV EBP,ESP  
0049B137  .>ADD ESP,-40  
0049B13A  .>PUSH EBX  
0049B13B  .>PUSH ESI  
0049B13C  .>PUSH EDI  
0049B13D  .>XOR ECX,ECX  
0049B13F  .>MOV DWORD PTR SS:[EBP-3C],ECX  
0049B142  .>MOV DWORD PTR SS:[EBP-40],ECX  
0049B145  .>MOV DWORD PTR SS:[EBP-34],ECX  
0049B148  .>MOV DWORD PTR SS:[EBP-38],ECX  
0049B14B  .>MOV DWORD PTR SS:[EBP-30],ECX  
0049B14E  .>MOV DWORD PTR SS:[EBP-28],ECX  
0049B151  .>MOV DWORD PTR SS:[EBP-2C],ECX  
0049B154  .>MOV DWORD PTR SS:[EBP-24],ECX  
0049B157  .>MOV EBX,EAX  
0049B159  .>MOV ESI,smartsea.004ACC08  
0049B15E  .>XOR EAX,EAX  
0049B160  .>PUSH EBP  
0049B161  .>PUSH smartsea.0049B7FB  
0049B166  .>PUSH DWORD PTR FS:[EAX]  
0049B169  .>MOV DWORD PTR FS:[EAX],ESP  
0049B16C  .>JMP smartsea.004D4000              //把mov    eax, [ebx+$0308]改成这个,跳到我们的代码  
0049B171    >NOP  
0049B172  .>XOR EDX,EDX  
0049B174  .>CALL smartsea.0042D0F8  

为便于理解,给出globalalloc,globallock的原型  

HGLOBAL GlobalAlloc(  

    UINT uFlags,    // 要申请的内存的标志,也就是说这块内存是什么类型的  
    DWORD dwBytes     // 要申请的内存大小  
  );  
LPVOID GlobalLock(  

    HGLOBAL hMem     // 你要锁定的那块内存的指针  
  );  
     
004D4000  6>PUSH 0FFFFF                        //我们要这么大的内存:)                      
004D4005  6>PUSH 42                            //GHND,标志具体可以查手册  
004D4007  E>CALL     //这个函数的地址可以用WIN32ASM查看,我这里是4069A0  
004D400C  A>MOV DWORD PTR DS:[4D4540],EAX      //把返回的地址指针保存起来,我存到了4D4540  
004D4011  5>PUSH EAX                            //我们要锁定他  
004D4012  E>CALL     //这个函数地址4069B8  
004D4017  A>MOV DWORD PTR DS:[4D4544],EAX      //把指针保存到4D4544  
004D401C  8>MOV EAX,DWORD PTR DS:[EBX+308]      //这是原来的程序,要恢复他(这里他没有用到寄存器,所以我们不用保存他们得值)  
004D4022  -E>JMP smartsea.0049B172              //返回了  

有了内存,我们就可以保存了,这么大一块内存,我决定不仅仅保存指针了,把那些字符串全保存起来,以后更便于写入文件不是吗?  

就是刚才这段:  

00468568  $>PUSH EBP  
00468569  .>MOV EBP,ESP  
0046856B  .>PUSH ECX  
0046856C  .>PUSH EBX  
0046856D  .>PUSH ESI  
0046856E  .>PUSH EDI  
0046856F  .>JMP smartsea.004D4027        //这里改了,跳到我们的程序  
00468574  .>MOV EBX,EAX  
00468576  .>MOV EDX,DWORD PTR SS:[EBP-4]  
00468579  .>MOV EAX,EBX  

这里我们也用到两个函数:一个是字符串拷贝,一个是获取字符串长度,本来我想用lstrcat这个字符串连接函数,但是程序里没有,要自己构造麻烦,所以自己来实现吧。原型如下  

LPTSTR lstrcpy(  

    LPTSTR lpString1,    // 目的空间指针  
    LPCTSTR lpString2     // 源字符串指针  
  );  

int lstrlen(  

    LPCTSTR lpString     // 要计算长度的字符串地址指针  
  );     

004D4027  PUSH EAX                      //发现他们有使用这些寄存器,而我们的操作会破坏他们的值,所以存起来先  
004D4028  PUSH ECX  
004D4029  PUSH EDX  
004D402A  MOV EBX,DWORD PTR SS:[EBP+8]  //记得我刚才说的这里存放着我们要的东西  
004D402D  CMP EBX,0                      //这个比较是因为,你会发现第一次的值是0,可能是stringgrid的初始化,对我们没用,而且会出错  
004D4030  JE SHORT smartsea.004D406B    //如果是0就返回去不操作  
004D4032  PUSH EBX                      //源字符串指针,给lstrcpy准备的  
004D4033  MOV ESI,DWORD PTR DS:[4D4544]  //还记得吗,这就是我们申请的内存空间指针存放处  
004D4039  MOV EBX,DWORD PTR DS:[4D4548]  //这个地址用来存放一个变量,这个变量就是字符串的长度,这样,我们可以实现字符串连接  
004D403F  LEA EBX,DWORD PTR DS:[EBX+ESI] //上面两个的和就指向我们要存放的目的地址的指针  
004D4042  PUSH EBX                      //压进去给lstecpy  
004D4043  CALL   //这个函数地址是4012F8  
004D4048  PUSH DWORD PTR DS:[4D4544]    //来测一下现在我们现在的字符串有多长  
004D404E  CALL   //地址是401308  
004D4053  MOV DWORD PTR DS:[4D4548],EAX  //把返回的长度值存进我们的变量空间  
004D4058  MOV WORD PTR DS:[EAX+ESI],0A0D //加入回车换行,目的是在保存的文件里可以一行显示一个EMAIL  
004D405E  MOV BYTE PTR DS:[EAX+ESI+2],0  //再加一个字符串结束标志NULL  
004D4063  ADD EAX,2                      //由于我们加了两个字节,所以长度变化了  
004D4066  MOV DWORD PTR DS:[4D4548],EAX  //再次保存  
004D406B  POP EDX                        //可以返回了  
004D406C  POP ECX  
004D406D  POP EAX  
004D406E  MOV DWORD PTR SS:[EBP-4],ECX  //这个都是源程序的东西,别忘了恢复  
004D4071  MOV ESI,EDX  
004D4073  JMP smartsea.00468574          //回去咯  

简单的解释一下,如果你觉得一头雾水的话,我们的目的是保存成这样的形式:  

green@sina.com/r/nlemon@sina.com/r/nupfeed@sina.com/r/n......  
这样我们在文件里才可以存成这样:  
green@sina.com  
lemon@sina.com  
upfeed@sina.com  

再回去理解一下,不难了吧。  

第二步算是搞定了,来搞最后的一步,经过了上面,发现原来也不难是吧?:)事实上这么简单的代码,我调了n次,改了n次,所以说。。。。不知道说什么好,可能我比较菜吧:)  

来看看保存按钮里有什么:  

0049E688  push    $00  
0049E68A  mov    cx, word ptr [$49E6A0]  
0049E691  mov    dl, $02  

* Possible String Reference to: '付费注册用户才能保存电邮'  
|  
0049E693  mov    eax, $0049E6AC  
|  
0049E698  call    004510A4  
0049E69D  ret  

没有什么有价值的东西,全部改掉!  

这是改后的:利用到messagebox原型如下  

int MessageBox(  

    HWND hWnd,    // 父窗体的句柄  
    LPCTSTR lpText,    // 要显示的字符串指针  
    LPCTSTR lpCaption,    // 标题栏上字符串的指针  
    UINT uType     // 消息框的类型  
  );  

注意到需要父窗体句柄,所以要到程序里去找找,把断点下在createwindowex很快就可以找到,但是我原先在这里范了一个错误,我直接用的是内存里的地址,忘了这对每台机器都是变动的,现在修正了一下,我把它保存起来了!  

所以首先找到这里:  

0044A0DE  MOV EDX,EAX                              ;  
0044A0E0  MOV ECX,84CA0000                        ; |  
0044A0E5  MOV EAX,DWORD PTR DS:[4AAAB8]            ; |  
0044A0EA  CALL smartsea.0040730C                  ; 这个进去就是creatwindowex,返回值是句柄存在eax里  
0044A0EF  JMP smartsea.004D4078                    //跳到我们的保存代码  
0044A0F4  NOP  
0044A0F5  CALL smartsea.00403B40  

004D4078  MOV DWORD PTR DS:[4D4550],EAX            //存到这  
004D407D  MOV DWORD PTR DS:[EBX+24],EAX            //源程序的东西恢复  
004D4080  LEA EAX,DWORD PTR DS:[EBX+7C]  
004D4083  JMP smartsea.0044A0F5  

0049E688  call    004A9426                  //到我们做一个函数那  
0049E68D  cmp    eax, +$00                //比较返回值,判断我们是保存还是取消  
0049E690  jz      0049E69C                  //取消的话是0,就跳  
0049E692  mov    eax, $004D43E9            //这里存放着success!  
0049E697  jmp    0049E6A1  
0049E69C  mov    eax, $004D43E0            //这里存着faliure!,  
0049E6A1  push    $00                      //MB_OK型  
0049E6A3  push    $004D4370                //这里存着字符串。。我的标志:)  
0049E6A8  push    eax                      //看看是成功还是失败咯  
0049E6A9  push    dword ptr [$4D4550]      //这个是句柄,怎么来的?当然是跟踪来的,把断点下在CREATEWINDOW很快就可以找到  

* Reference to: user32.MessageBoxA()  
|  
0049E6AF  call    00401288  
0049E6B4  ret  

来看看我们的函数(有点长,但很简单:)用到了这几个函数:  

BOOL GetSaveFileName(  

    LPOPENFILENAME lpofn     // 指向OPENFILENAME类型的结构指针  
  );  

这个就是结构体,参数很多,查手册吧  
typedef struct tagOFN { // ofn  
    DWORD        lStructSize;  
    HWND          hwndOwner;  
    HINSTANCE    hInstance;  
    LPCTSTR      lpstrFilter;  
    LPTSTR        lpstrCustomFilter;  
    DWORD        nMaxCustFilter;  
    DWORD        nFilterIndex;  
    LPTSTR        lpstrFile;  
    DWORD        nMaxFile;  
    LPTSTR        lpstrFileTitle;  
    DWORD        nMaxFileTitle;  
    LPCTSTR      lpstrInitialDir;  
    LPCTSTR      lpstrTitle;  
    DWORD        Flags;  
    WORD          nFileOffset;  
    WORD          nFileExtension;  
    LPCTSTR      lpstrDefExt;  
    DWORD        lCustData;  
    LPOFNHOOKPROC lpfnHook;  
    LPCTSTR      lpTemplateName;  
} OPENFILENAME;  

HANDLE CreateFile(  

    LPCTSTR lpFileName,    // 文件名指针  
    DWORD dwDesiredAccess,    // 授权的模式(读,写,还是都有)  
    DWORD dwShareMode,    // 共享模式  
    LPSECURITY_ATTRIBUTES lpSecurityAttributes,    // 安全属性  
    DWORD dwCreationDistribution,    // 建立模式  
    DWORD dwFlagsAndAttributes,    // 文件属性  
    HANDLE hTemplateFile     // 临时文件  
  );  
BOOL WriteFile(  

    HANDLE hFile,    // 要写入的文件句柄,一般由CREATEFILE返回的值就是  
    LPCVOID lpBuffer,    // 要写入文件的缓冲区指针  
    DWORD nNumberOfBytesToWrite,    // 写入多少字节  
    LPDWORD lpNumberOfBytesWritten,    // 已写入的字节  
    LPOVERLAPPED lpOverlapped     // 重叠模式指针  
  );  

004A9426  push    ebp                            //保存寄存器的值,不知道用了哪些,都存吧保险:)  
004A9427  push    ebx  
004A9428  push    esi  
004A9429  push    edi  
004A942A  mov    dword ptr [$4D4390], $0000004C  //下面是结构体的一些参数,这是整个结构体的大小,存放到从4D4390开始的一段空间里  
004A9434  push    dword ptr [$4D4550]            //这个是窗体句柄,上面提到过  
004A943A  pop    dword ptr [$4D4394]            //存到第二个DWORD  
004A9440  push    dword ptr [$4AC4D8]            //这是模块句柄,跟踪程序开始的GETMODULEHANDLE就可以找到  
004A9446  pop    dword ptr [$4D4398]            //存到第3个  
004A944C  mov    dword ptr [$4D439C], $004D4350 //这个是文件过滤的参数我们这里是ALL FILES和TEXT FILES存在4D4350处可以用16进制编辑器预先写入  
004A9456  mov    dword ptr [$4D43AC], $004D4420  //文件名要存放的地方  
004A9460  mov    dword ptr [$4D43A8], $00000002  //缺省状态的过滤参数是TEXTFILE  
004A946A  mov    dword ptr [$4D43B0], $00000104  //文件名最大长度不超过260字节  
004A9474  mov    dword ptr [$4D43C4], $00282806  //文件的标志,查手册  
004A947E  mov    dword ptr [$4D43C0], $004D4370  //标题栏上的字符串,还是我:)  
004A9488  push    $004D4390                      //结构体指针给getsavefilename  

* Reference to: comdlg32.GetSaveFileNameA()  
|  
004A948D  call    0044C534  
004A9492  cmp    eax, +$01                      //比较一下如果是取消就返回  
004A9495  jnz    004A94FA                        
004A9497  push    $00                            //createfile的七个参数  
004A9499  push    $20  
004A949B  push    $02  
004A949D  push    $00  
004A949F  push    $03  
004A94A1  push    $C0000000  
004A94A6  push    $004D4420  

* Reference to: kernel32.CreateFileA()  
|  
004A94AB  call    00401210  
004A94B0  mov    dword ptr [$4D454C], eax        //文件句柄存起来  
004A94B5  push    dword ptr [$4D4544]            //看看现在我们那个内存空间里有多长的字符串,好准备写入  

* Reference to: kernel32.lstrlenA()  
|  
004A94BB  call    00401308  
004A94C0  push    $00                            //写入文件用的5个参数  
004A94C2  push    $004D4550  
004A94C7  push    eax  
004A94C8  push    dword ptr [$4D4544]  
004A94CE  push    dword ptr [$4D454C]  

* Reference to: kernel32.WriteFile()  
|  
004A94D4  call    00401260  
004A94D9  push    dword ptr [$4D4544]  
|  
004A94DF  call    004069D0我的diype历程之一(smartsearch保存功能之添加)  
我的diype历程之一(smartsearch保存功能之添加)  
我的diype历程之一(smartsearch保存功能之添加)  

004A94E4  push    dword ptr [$4D4540]  

* Reference to: kernel32.GlobalFree()  
|  
004A94EA  call    004069B0  
004A94EF  push    dword ptr [$4D454C]  

* Reference to: kernel32.CloseHandle()  
|  
004A94F5  call    00401208  
004A94FA  pop    edi  
004A94FB  pop    esi  
004A94FC  pop    ebx  
004A94FD  pop    ebp  
004A94FE  ret  

后记:似乎看起来没做多少工作,不过我觉得很累了:)也许我的精力比较差把,希望能抛砖引玉。不足之处还望大家多指点!  
转载请注明出处,并保持完整性,谢谢! 
    
    
     
    
    
     

相关阅读 Windows错误代码大全 Windows错误代码查询激活windows有什么用Mac QQ和Windows QQ聊天记录怎么合并 Mac QQ和Windows QQ聊天记录Windows 10自动更新怎么关闭 如何关闭Windows 10自动更新windows 10 rs4快速预览版17017下载错误问题Win10秋季创意者更新16291更新了什么 win10 16291更新内容windows10秋季创意者更新时间 windows10秋季创意者更新内容kb3150513补丁更新了什么 Windows 10补丁kb3150513是什么

文章评论
发表评论

热门文章 去除winrar注册框方法

最新文章 比特币病毒怎么破解 比去除winrar注册框方法 华为无线路由器HG522-C破解教程(附超级密码JEB格式文件京东电子书下载和阅读限制破解教UltraISO注册码全集(最新)通过Access破解MSSQL获得数据

人气排行 华为无线路由器HG522-C破解教程(附超级密码JEB格式文件京东电子书下载和阅读限制破解教UltraISO注册码全集(最新)qq相册密码破解方法去除winrar注册框方法(适应任何版本)怎么用手机破解收费游戏华为无线猫HG522破解如何给软件脱壳基础教程