·汉化新世纪 ·汉化新世纪论坛 ·百家争鸣 ·论坛集萃 ·汉化问答 ·软件介绍
文章首页 >> 汉化教学 >> 特殊汉化 >> 用pediy实现为程序添加对话框和网址的功能    Creative Commons License,创作共用协议(中文版)  署名 非商业性使用 禁止演绎

用pediy实现为程序添加对话框和网址的功能

作者: 雅枫 来源:汉化教学 时间:2004-03-20 点击:15604

原帖在此

论坛上经常有人问如何在软件上加上自己的对话框,或自己网站的连接,但却不好找教程,为什么呢?一是这是非常初级的技术,高手们懒得写;再就是包括我在内,对这种行为(在人家软件上胡乱加自己的东东)也是持保留态度的,相对来说,我更想实现一些更加有用些的功能。
首先声明一点,你用我说的技术,挨了骂,你可千万别怨我,也千万别说我教你的(没办法,穷呀,人家告我我可打不起官司:),也别说是在汉化新世纪上学的:)说不定人家会说汉化新世纪上一大群菜鸟,不会干别的,只会教这种没用的,别人不屑用的技术。其实早些时候我写的的《pediy之画猫篇》也是讲的这方面的内容,只不过用的api多一些,调试也稍微复杂一点,我没说明白,让新手也看不明白,所以我加上这一篇,并且尽量减轻工作量,为的是让感兴趣的朋友都学会。
时间有限,废话少说,介绍两个用到的api先一个是ShellExecuteA,这是用来加连接的函数,另一个是DialogBoxParamA这是用来显示对话框的。分别在shell32.dll与user32.dll两个库里边。大家会说还有个DialogBoxA更简单一些,为什么不用呢?因为这个函数是根本不存在的,编译器会自动把后者转化成前者。下边是我从ollydbg里边拷出来的两段调用代码(做过一定的修改)。

PUSH 0A ; /IsShown
PUSH 00 ; |DefDir => NULL
PUSH 00 ; |Parameters
PUSH 00400320 ; |FileName = "http://bbs.hanzify.org"
PUSH 00 ; |Operation => NULL
PUSH 00 ; |hWnd => NULL
CALL [ShellExecuteA] ; \ShellExecuteA

就加打开网页这个功能来说,我们可以完全不必在乎上面的api的参数的意义,只需要在"FileName"这一项的push中压入我们想要执行命令行就ok了,也就是说,先在某处建立一个字串,如建在0x300处,用偏移量转换器算出调用码是400300,然后找个地方直接照搬上边的代码,只把从上边数第4个push 00400100改成push 00400300,然后运行这段代码就可以了,使不是很简单?


PUSH 0 ; /lParam = NULL
PUSH 00401020 ; |DlgProc = 00401020
PUSH EDX ; |hOwner
PUSH 67 ; |pTemplate = 67
PUSH EAX ; |hInst => NULL
CALL [DialogBoxParamA] ; \DialogBoxParamA

这个函数需要我们注意的参数相对多一点:其中从上边数第二个参数“DlgProc”非常让人头痛,因为这是DialogBoxParamA的回调函数,也就是处理对话框响应的函数,一般代码量比较大,我一般是先用汇编语言写出程序,然后根据返汇编代码往里输。累不说,还容易出错,不过我想到了一个比较有天赋的办法:)可以轻轻松松地实现一个简单的对话框:其实我们加的对话框也就只有一个“确定”按钮吧?跟那个“关于”对话框的行为应该差不多一致吧?所以直接利用关于对话框的回调函数部就可以了嘛,还可以保持原程序的风格,这就是这篇文章的精要所在了:)哈哈!(做自我陶醉状……%^&^%&&*@)谁在朝我扔西红柿?)。再有就是下边的“hOwner”这个参数,这个需要父窗口句柄,也不难,反正跟“关于”对话框也是一个“父窗口”(即主窗口)照搬即可!接下来就是我们非常感兴趣的参数“pTemplate”了,这就是指定资源模板的参数!上边的模板是67h就是十进制的103,即显示资源中ID号为103的对话框(ResHacker中写着呢:)基础知识介绍完了。我就以看雪(段钢)老兄的一个破解例子traceme来实战一下,感兴趣的go!go!go!

先做准备工作,反汇编调试我用ollydbg,建议大家也用这个;十六进制编辑器,可以用ue,也可以随便选一个;lord pe一个非常棒的pe编辑工具;梁大师的偏移量转换器,哦还有一个就是ResHacker!大体上就这些啦!然后我再吹吹ollydbg(对这个工具反感的略去下段话),反正自从用上WIN2000导致TRW2000倒下后,它基本上是我的主力工具了,windows图型界面,比w32dasm更详尽的注释(我十分欣赏它对api的注释),加上比较强大的动态调试能力(当然比不上softice)。并且它十分容易上手,对api的注释基本一一对应,一目了然,让人看了十分舒服。相对来说,W32DASM就有点乱,对于熟悉汇编语言的人来说不是问题,但对新手就会有些晕了。可惜大部分汉化教程推出时还没有这个工具,所以都是用的W32DASM,无疑也增加了学习难度……,还有一个我常用的是W32DASM,虽然我用的并不多,但遇到改DLL,我一般还是用W32DASM反汇编(当然调试也不是非常难),IDA PRO反汇编能力强是没得说,可那速度……并且使用复杂,虽反汇编代码比较清楚但仍是不易上手,SoftICE甭提了,我原来用的4.05(老版本)跟2000的SP4有严重冲突,搞的连续两次系统崩溃。再也没心情安装了,唉只不过到了非用不可时还得用呀……
所以我建议,如果是新手干脆从ollydbg开始得啦,用w32dasm做辅助,以后再学si/trw……
其实做这个非常关键的一点就是:如何把代码加到该加的位置,这是比较难的,我后边说,现在我们做的就是改一下资源,加上两个菜单项id分别是40003与40004和一个对话框资源id是104(68h),前一个大家都会,不用我多嘴,后边一个可以先用resHacker把“关于”对话框的资源导出存为res格式,然后再用reshacker打开这个res把原来的id号103改成104保存退出,然后再打开程序,作为一个新资源导入就可以了。这个对于咱们搞汉化的不是什么难题吧?我也不断截图了。现在再运行程序,菜单是有了(如图)

但是点击它没有响应呀!自然了,根本就没有什么响应代码,有响应才怪呢!别急别急下边就是加代码的的方法了。(艰巨的任务,休息一下先)。

先说说程序是如何处理菜单响应的(尽量简单易懂地说):当你按下菜单执行相应的命令后,CreateDialogBoxParamA会调用窗口回调函数来处理,即把包含菜单命令的信息作为参数送给窗口回调函数,因为一般界面中菜单或按钮有多个,所以很明显会有下面的类型的代码:

cmp eax,xxxx(菜单id) ;比较一下时不是这个菜单命令

jz xxxxxxxx(偏移量) ;如果时就转到这个菜单

jmp x1 ;如果不是就必是否为下一个菜单

……

x1:cmp eax,xxx2(菜单id2) ;比较一下时不是这个菜单

jz xxxxxxxx2 ;如果时就转到这个菜单

jmp x3 ;否则判断下一个

……

这就是我们加代码的地方了:)如果想加在这两个菜单之间则改成下边的样子:



cmp eax,xxxx(菜单id) ;比较一下时不是这个菜单命令

jz xxxxxxxx(偏移量) ;如果时就转到这个菜单

jmp myadd1 ;如果不是就必是否为下一个菜单*************

……

x1:cmp eax,xxx2(菜单id2) ;比较一下时不是这个菜单

jz xxxxxxxx2 ;如果时就转到这个菜单

jmp x3 ;否则判断下一个

……

myadd1:cmp eax,9c43(40003的十六进制是9c43)***************

jz myadd2 ;;跳到我们菜单的响应函数*****************

jmp x1*****************

myadd2:;我们的响应函数***************

……

jmp x1**************

加有***********的行是我们加上的部分,不难看出,我们把我们的代码嵌入到了原程序里边(对汇编不太熟悉的朋友可以翻翻书)。我们来一下实战:

用OllyDbg反汇编程序,照图示的方法把断点下在CreateDialogBoxParamA上:在主窗口反汇编代码区点击右键如下图,汉化版是:“搜索”-〉“全部交互调用”

然后就出现了下边的窗口:

点击上边的条排序,很容易就找到了这个函数,在这个函数上点右键按下图所示的方法就可以设定每次到这个函数的断点。

然后回到主界面,按F9运行,就中断到了第一个调用处了,不用说,肯定是主窗口了(注意,大部分主窗口都是用的CreateWindowsEx这个函数而不是CreateDialogBoxParamA)

上边的DlgProc参数已经写出了窗口回调函数的地址00401d0,这时候只要这个地址去分析就可以找到修改代码的地方。我也是在这儿找的,不过主窗口不是用CreateDialogBoxParamA生成的就不太通用了(当然也可以拦截CreateWindowsEx),所以我们不管这里,继续按F9出现了TRACEME的主界面,然后点击一下帮助菜单中的“关于”,我们看到程序又中断在了CreateDialogBoxParamA处:

往上一看就看见了两个cmp指令,我们分析一下代码:



RETN 10

CMP EAX,3F6 ;如果是3F6

JE SHORT TRACEME.004012A3 ;则跳转到4012A3处

CMP EAX,9C42 ;这不是关于菜单40002的id么?呵呵

JNZ SHORT TRACEME.004012C0 ;如不是关于菜单,就跳走,是则执行4012A3

4012A3: MOV EDX,DWORD PTR SS:[ESP+100] ; Cases 3F6,9C42 of switch 0040115E

MOV EAX,DWORD PTR DS:[4054E0]

PUSH 0 ; /lParam = NULL

PUSH TRACEME.00401020 ; |DlgProc = TRACEME.00401020

PUSH EDX ; |hOwner

PUSH 67 ; |pTemplate = 67

PUSH EAX ; |hInst => 00400000

CALL DWORD PTR DS:[<&USER32.Dialo> ; \DialogBoxParamA

POP EDI ; Default case of switch 0040115E

XOR EAX,EAX

大家想必也看到了4012A3处的注释,正是响应3F6与9C42的地方,后者是关于菜单,前者则是主界面上的关于按钮的ID,找到了地方,我们就可以增加上我们的代码了,我们加在我们的老地方:400300处那么我们就要把JNZ SHORT TRACEME.004012C0这句改成JMP 400300了,等等看看下边的代码:

0040129A . 74 07 JE SHORT TRACEME.004012A3

0040129C . 3D 429C0000 CMP EAX,9C42

004012A1 . 75 1D JNZ SHORT TRACEME.004012C0

004012A3 > 8B9424 0001000>MOV EDX,DWORD PTR SS:[ESP+100]



JNZ SHORT TRACEME.004012C0这一句是个短跳转只有2个字节,而改成我们的JMP400300则需要6个字节!即FF1500034000,怎么办?只有把上句或下句一齐改到我们的400300处了!把光标停在CMP EAX,9C42这一句上,然后按空格键,出现如下窗口,直接在里边改成JMP 400300,然后点击“汇编(Assemble)”就可以了。然后点击右键菜单,选择“复制到可执行文件”“全部复制”就可以了。

接下来就是在400300处加上我们的代码:用ollydbg打开上次修改后的文件如traceme2.exe反汇编,然后从“插件”-〉命令行,打开命令行工具,写入“bp 400300”回车后如图:

关闭这个窗口,按F9运行,然后点击帮助菜单,程序断在了400300处!然后如上边一样写上:

00400300 3D 429C0000 CMP EAX,9C42

00400305 -0F84 980F0000 JE TRACEME2.004012A3

0040030B 3D 439C0000 CMP EAX,9C43

00400310 74 1E JE SHORT TRACEME2.00400330

00400312 3D 449C0000 CMP EAX,9C44

00400317 74 47 JE SHORT TRACEME2.00400360

00400319 -E9 A20F0000 JMP TRACEME2.004012C0

然后就是在400330与400360处加上我们的响应代码:

PUSH 0A ; /IsShown

PUSH 00 ; |DefDir => NULL

PUSH 00 ; |Parameters

PUSH 004003F0 ; |FileName = "http://bbs.hanzify.org"

PUSH 00 ; |Operation => NULL

PUSH 00 ; |hWnd => NULL

CALL [ShellExecuteA] ; \ShellExecuteA

其中我们在4003F0(0X3F0)的地方加上了HTTP://BBS.HANZIFY.ORG

这个字串,再由就是程序的输入表中没有ShellExecuteA这个函数,我们可用lord pe给他加上,具体参见我写的另一篇文章“如何为程序添加api”半仙说用lord pe增加api会添加一个新段,导致资源无法编辑,这个问题确实是有,不过仅限于资源编辑后大小比原来大的情况,如果出现了这个问题,可以用lord pe删了被覆盖的函数重新再加,然后改调用,不过保险起见也为了避免麻烦,还是把加函数这个工作放在汉化完后再做。修改后的代码如下:

00400330 6A 0A PUSH 0A

00400332 6A 00 PUSH 0

00400334 6A 00 PUSH 0

00400336 68 F0034000 PUSH TRACEME2.004003F0

0040033B 6A 00 PUSH 0

0040033D 6A 00 PUSH 0

0040033F FF15 1C704000 CALL DWORD PTR DS:[<&shell32.ShellExecuteA>]

00400345 -E9 760F0000 JMP TRACEME2.004012C0

现在保存到源程序,运行试试看?作者主页这个菜单有响应了,打开了我们经常上的“汉化新世纪论坛”:)是不是比较有成就感?

再接再厉,我们在400350再加上显示一个对话框的代码,让它产生一个对话框!



00400357 6A 00 PUSH 0

00400359 68 20104000 PUSH TRACEME2.00401020

0040035E 52 PUSH EDX

0040035F 6A 68 PUSH 68

00400361 6A 00 PUSH 0

00400363 FF15 C8404000 CALL DWORD PTR DS:[USER32.DialogBoxParamA]

00400369 -E9 520F0000 JMP TRACEME2.004012C0



大家可以跟第二次中断下来的那幅图(下图)

比较看,几乎就是原样抄下来了:只是把窗口模版改成了68(就是104),其中那句MOV EDX,DWORD PTR SS:[ESP+100] 作用是取得父窗口句柄,这里一定要注意,他用的是esp而不是通常的ebp来寻址的,所以如果两个过程中动用了堆栈(如push或call指令)则指令也会不同,不过我们只用了jmp并没有动到什么堆栈,所以直接照抄过去就可以了。

花了一上午,终于写完了(幸亏老板出差去了啊:),也不知道有没有把这个技术说清楚,如果还有什么不清楚的地方,可以到汉化新世纪论坛上问(就是这里嘛~~代贴者注:)),附件是原程序和我修改的一个程序,大家可以比较参考一下。


 点击下载该文件

 

汉化新世纪 责任编辑: 乾 .:|:. 标签(Tag): PEDIY

·上一篇: Delphi 类程序界面汉化第八法 ·下一篇: .net汉化系列之一——.net程序汉化初探

· 版权申明: 本文引自《汉化教学》,如有版权疑问请及时联系本站,以便本站处理。

· 转载申明: 本文引自《汉化教学》[ 作者: 雅枫],如需转载请直接联系原始作者,并请注明原始出处。

相关文章                                                                                发表评论 打印此文 关闭窗口

| 设为首页 | 加入收藏 | 联系我们 | 友情链接
Creative Commons License,创作共用协议(中文版)  署名 非商业性使用 禁止演绎
本站内容,除转载或版权特别申明的内容外,皆遵守 创造共用协议中文版之“署名-非商业性使用-禁止演绎 2.5 中国大陆”条款
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 2.5 China License.
本网站内容源自汉化新世纪论坛的摘录和汉化新世纪成员的原创文章。
凡汉化新世纪论坛的文字皆默认为汉化新世纪与原作者共同拥有并授权发布。
如对本站发布文章有所异议请来信告知,我们将及时删除。
凡商业摘录本站文字请先与我们联系,本站将保留非授权商业发布的追究权利。
凡非商业摘录本站文字请明显注明出处和原作者,并不得改动,凡改动必先征求原作者同意。
苏ICP备05002283号