文章导航PC6首页软件下载单机游戏安卓资源苹果资源

pc软件新闻网络操作系统办公工具编程服务器软件评测

安卓新闻资讯应用教程刷机教程安卓游戏攻略tv资讯深度阅读综合安卓评测

苹果ios资讯苹果手机越狱备份教程美化教程ios软件教程mac教程

单机游戏角色扮演即时战略动作射击棋牌游戏体育竞技模拟经营其它游戏游戏工具

网游cf活动dnf活动lol周免英雄lol礼包

手游最新动态手游评测手游活动新游预告手游问答

您的位置:首页精文荟萃破解文章 → 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破解如何给软件脱壳基础教程