转贴自 FCG论坛
http://www.fcgchina.com/ctb
作者:you_known
[原创]破解技术在汉化过程中的应用之AsfTool篇
很久没写文章了,写出来却又不知道贴到哪个区~苦恼......
===========================================
声明:
1.本文可能夹杂大量技术术语,适用于有一定Delphi编程经验、了解破解及汉化过程的用户阅读。如果您对此感到不快,请勿继续阅读。
3.本文仅仅从技术角度讨论汉化问题的一些思路,不会提供文中涉及的内容下载,请自行查找。勿将之用于侵犯版权等非法目的,或损害他人利益。如果您对此感到失望,请勿继续阅读。
4.本文系本人(you_known@163.com)原创,版权归作者所有,转载前请先征得作者同意并保持文章的完整性。
AsfTools 3.1是一款修复、转换Asf流媒体的小工具,本身是免费软件。或许正因为是免费软件,作者不希望自己的辛苦工作被人篡改,程序中写入了自效验代码,防止程序被修改。而对于汉化来说,不得不对程序本身进行修改,所以第一步就是去除程序的自效验:
首先,我们必须确认源程序是何种语言编写,以便利用工具针对性的分析。祭出FileInfo(PEid等也可)查看原程序,显示为UPX加壳,很容易的脱掉壳,现出原形为Delphi编写程序。双击运行脱壳后的程序,发现程序界面闪现一下就退出了,确定其含有自效验代码。
下面再看它是如何进行自效验的。既然是Delphi程序,自然拿出Delphi的反汇编利器DeDe将脱壳后的程序反汇编,DeDe将他顺利的搞定,于是它就什么秘密都没有了~回忆一下,它是先显示About对话框,然后需要用户确认后进入主界面,在主界面闪现后退出,根据经验,自效验代码部分应写在主界面窗体中。既然主界面会显示,该代码自然不在FormCreate事件中,猜测会在FormShow事件中,找到TMainForm的FormShow代码:
代码:
004AF0B4 55 push ebp
004AF0B5 8BEC mov ebp, esp
004AF0B7 33C9 xor ecx, ecx
004AF0B9 51 push ecx
004AF0BA 51 push ecx
004AF0BB 51 push ecx
004AF0BC 51 push ecx
004AF0BD 51 push ecx
004AF0BE 51 push ecx
004AF0BF 51 push ecx
004AF0C0 51 push ecx
004AF0C1 53 push ebx
004AF0C2 8945FC mov [ebp-$04], eax
004AF0C5 33C0 xor eax, eax
004AF0C7 55 push ebp
* Possible String Reference to: '橐R?腚[?]?
|
004AF0C8 68F5F14A00 push $004AF1F5
***** TRY
|
004AF0CD 64FF30 push dword ptr fs:[eax]
004AF0D0 648920 mov fs:[eax], esp
004AF0D3 55 push ebp
* Reference to: main.Proc_004AEE08
|
004AF0D4 E82FFDFFFF call 004AEE08
004AF0D9 59 pop ecx
004AF0DA 8D55F8 lea edx, [ebp-$08]
004AF0DD 33C0 xor eax, eax
* Reference to: System.ParamStr(Integer):String;
|
004AF0DF E8D839F5FF call 00402ABC
004AF0E4 8B45F8 mov eax, [ebp-$08]
* Reference to: main.Proc_004ABFE0
|
004AF0E7 E8F4CEFFFF call 004ABFE0
<!-- CETagParser ~color=red~ --><font color="red"><!-- /CETagParser -->004AF0EC 8BD8 mov ebx, eax
004AF0EE B880841E00 mov eax, $001E8480
004AF0F3 2BC3 sub eax, ebx
004AF0F5 3D80641900 cmp eax, $00196480
004AF0FA 740D jz 004AF109
* Reference to MainForm
|
004AF0FC 8B45FC mov eax, [ebp-$04]
* Reference to: Forms.TCustomForm.Close(TCustomForm);
|
<!-- CETagParser ~color=red~ --><font color="red"><!-- /CETagParser -->004AF0FF E8C4E8FAFF call 0045D9C8
004AF104 E9D1000000 jmp 004AF1DA
看这里的004AF0FF E8C4E8FAFF call 0045D9C8;Forms.TCustomForm.Close(TCustomForm),这个是Delphi关闭窗体的函数,刚刚才Show出来怎么就Close掉,有问题,往上看到有一个减法运算,比较某个数字与$001E8480的差是否等于$00196480,若相等则跳走,否则关闭窗体。先将$001E8480-$00196480得到$52000转为十进制335872,这个数很眼熟啊,点原程序的属性一看,哇勒~就是原始文件的大小嘛,嘿嘿,这个就是效验程序是否被脱壳了,要是脱了自然大小就不一样了。改掉它不管什么大小都继续:
代码:
004AF0FA EB0D jmp 004AF109
好高兴得运行一下,奇怪了,半天没动静,只听到硬盘哗啦啦的转,MD,还有暗桩~再来继续往下看:
代码:
004AF109 8D55EC lea edx, [ebp-$14]
* Possible String Reference to: '路径'
|
004AF10C B80CF24A00 mov eax, $004AF20C
* Reference to: Unit_00408010.Proc_0040DC78
|
004AF111 E862EBF5FF call 0040DC78
004AF116 FF75EC push dword ptr [ebp-$14]
004AF119 681CF24A00 push $004AF21C
004AF11E 8D55E8 lea edx, [ebp-$18]
* Possible String Reference to: 'windir'
|
004AF121 B828F24A00 mov eax, $004AF228
* Reference to: Unit_00408010.Proc_0040DC78
|
004AF126 E84DEBF5FF call 0040DC78
004AF12B FF75E8 push dword ptr [ebp-$18]
004AF12E 681CF24A00 push $004AF21C
004AF133 8D55E4 lea edx, [ebp-$1C]
* Possible String Reference to: 'windir'
|
004AF136 B828F24A00 mov eax, $004AF228
* Reference to: Unit_00408010.Proc_0040DC78
|
004AF13B E838EBF5FF call 0040DC78
004AF140 FF75E4 push dword ptr [ebp-$1C]
* Possible String Reference to: 'system'
|
004AF143 6838F24A00 push $004AF238
004AF148 681CF24A00 push $004AF21C
004AF14D 8D55E0 lea edx, [ebp-$20]
* Possible String Reference to: 'windir'
|
004AF150 B828F24A00 mov eax, $004AF228
* Reference to: Unit_00408010.Proc_0040DC78
|
004AF155 E81EEBF5FF call 0040DC78
004AF15A FF75E0 push dword ptr [ebp-$20]
* Possible String Reference to: 'system32'
|
004AF15D 6848F24A00 push $004AF248
004AF162 8D45F0 lea eax, [ebp-$10]
004AF165 BA09000000 mov edx, $00000009
* Reference to: System.Proc_00404E20
|
004AF16A E8B15CF5FF call 00404E20
004AF16F 8B55F0 mov edx, [ebp-$10]
004AF172 8D4DF4 lea ecx, [ebp-$0C]
* Possible String Reference to: 'wmvcore.dll'
|
004AF175 B85CF24A00 mov eax, $004AF25C
* Reference to: Unit_00408010.Proc_00409708
|
004AF17A E889A5F5FF call 00409708
004AF17F 837DF400 cmp dword ptr [ebp-$0C], +$00
004AF183 753A jnz 004AF1BF
* Possible String Reference to: '警告:在您的系统中发现有视频组件丢失
| !请安装"Microsoft Media Encoder 7.1
| ".它可以免费从
www.microsoft.com获得
| .您可以继续使用但某些功能会被禁用.'
|
004AF185 B870F24A00 mov eax, $004AF270
* Reference to: Dialogs.ShowMessage(AnsiString);
|
004AF18A E8CDA4F8FF call 0043965C
* Reference to MainForm
|
004AF18F 8B45FC mov eax, [ebp-$04]
* Reference to control TMainForm.SpeedButton10 : TSpeedButton
|
004AF192 8B80B8030000 mov eax, [eax+$03B8]
004AF198 33D2 xor edx, edx
004AF19A 8B08 mov ecx, [eax]
* Reference to method TSpeedButton.SetEnabled(Boolean)
|
004AF19C FF5164 call dword ptr [ecx+$64]
* Reference to MainForm
|
004AF19F 8B45FC mov eax, [ebp-$04]
* Reference to control TMainForm.SpeedButton11 : TSpeedButton
|
004AF1A2 8B80BC030000 mov eax, [eax+$03BC]
004AF1A8 33D2 xor edx, edx
004AF1AA 8B08 mov ecx, [eax]
* Reference to method TSpeedButton.SetEnabled(Boolean)
|
004AF1AC FF5164 call dword ptr [ecx+$64]
* Reference to MainForm
|
004AF1AF 8B45FC mov eax, [ebp-$04]
* Reference to control TMainForm.SpeedButton13 : TSpeedButton
|
004AF1B2 8B80C4030000 mov eax, [eax+$03C4]
004AF1B8 33D2 xor edx, edx
004AF1BA 8B08 mov ecx, [eax]
* Reference to method TSpeedButton.SetEnabled(Boolean)
|
004AF1BC FF5164 call dword ptr [ecx+$64]
<!-- CETagParser ~color=red~ --><font color="red"><!-- /CETagParser -->004AF1BF B887D61200 mov eax, $0012D687
004AF1C4 2BC3 sub eax, ebx
004AF1C6 3D87B60D00 cmp eax, $000DB687
004AF1CB 740D jz 004AF1DA
* Reference to: Unit_00488EF4.Proc_00489408
|
004AF1CD E836A2FDFF call 00489408
* Reference to MainForm
|
004AF1D2 8B45FC mov eax, [ebp-$04]
* Reference to: Forms.TCustomForm.Close(TCustomForm);
|
<!-- CETagParser ~color=red~ --><font color="red"><!-- /CETagParser -->004AF1D5 E8EEE7FAFF call 0045D9C8
原来这里004AF1D5 E8EEE7FAFF call 0045D9C8还有一处效验,和上面的一样嘛,就是两个常数变了$0012D687-$000DB687还是等于$52000,还是看文件大小,照样改掉:
代码:
004AF1CB EB0D jmp 004AF1DA
再来运行,这回没问题了……
代码:
004AF1DA 33C0 xor eax, eax
004AF1DC 5A pop edx
004AF1DD 59 pop ecx
004AF1DE 59 pop ecx
004AF1DF 648910 mov fs:[eax], edx
****** FINALLY
|
* Possible String Reference to: '[?]?
|
004AF1E2 68FCF14A00 push $004AF1FC
004AF1E7 8D45E0 lea eax, [ebp-$20]
004AF1EA BA07000000 mov edx, $00000007
* Reference to: System.@LStrArrayClr(void;void;Integer);
|
004AF1EF E8D858F5FF call 00404ACC
004AF1F4 C3 ret
* Reference to: System.@HandleFinally;
|
004AF1F5 E95252F5FF jmp 0040444C
004AF1FA EBEB jmp 004AF1E7
****** END
|
004AF1FC 5B pop ebx
004AF1FD 8BE5 mov esp, ebp
004AF1FF 5D pop ebp
004AF200 C3 ret
再来看看如何将加密的字符串汉化过来。经过初步汉化,程序界面的大部分内容都已经是中文显示,但是关于对话框仍旧是英文界面,先从这里下手,控件的字符串都是在其显示之前被赋予的,可能会放在FormCreate、FormShow、FormActivate等事件代码中,通常来讲会是FormCreate,这个是该窗体所有代码中最先被执行的,查找TAboutForm的FormCreate汇编代码:
引用:
procedure TAboutForm.FormCreate(Sender : TObject);
begin
(*
00489A0C 55 push ebp
00489A0D 8BEC mov ebp, esp
00489A0F B904000000 mov ecx, $00000004
00489A14 6A00 push $00
00489A16 6A00 push $00
00489A18 49 dec ecx
00489A19 75F9 jnz 00489A14
00489A1B 51 push ecx
00489A1C 53 push ebx
00489A1D 8BD8 mov ebx, eax
00489A1F 33C0 xor eax, eax
00489A21 55 push ebp
* Possible String Reference to: '橹??脎?]?
|
00489A22 68F19A4800 push $00489AF1
***** TRY
|
00489A27 64FF30 push dword ptr fs:[eax]
00489A2A 648920 mov fs:[eax], esp
00489A2D 8D55F4 lea edx, [ebp-$0C]
* Possible String Reference to: 'pluvL}rK"gn~rI'
|
00489A30 B8089B4800 mov eax, $00489B08
* Reference to: Unit_00488EF4.Proc_004890F4
|
00489A35 E8BAF6FFFF call 004890F4
00489A3A 8B45F4 mov eax, [ebp-$0C]
00489A3D 8D55F8 lea edx, [ebp-$08]
* Reference to: Unit_00488EF4.Proc_004890F4
|
00489A40 E8AFF6FFFF call 004890F4
00489A45 8B45F8 mov eax, [ebp-$08]
00489A48 8D55FC lea edx, [ebp-$04]
* Reference to: Unit_00488EF4.Proc_004890F4
|
00489A4B E8A4F6FFFF call 004890F4
00489A50 8B55FC mov edx, [ebp-$04]
00489A53 8BC3 mov eax, ebx
* Reference to: Controls.TControl.SetText(TControl;TCaption);
|
00489A55 E8166AFBFF call 00440470
00489A5A 8D55EC lea edx, [ebp-$14]
* Possible String Reference to: 'Ez'
|
00489A5D B8209B4800 mov eax, $00489B20
* Reference to: Unit_00488EF4.Proc_004890F4
|
00489A62 E88DF6FFFF call 004890F4
00489A67 8B45EC mov eax, [ebp-$14]
00489A6A 8D55F0 lea edx, [ebp-$10]
* Reference to: Unit_00488EF4.Proc_004890F4
|
00489A6D E882F6FFFF call 004890F4
00489A72 8B55F0 mov edx, [ebp-$10]
* Reference to control TAboutForm.Button1 : TButton
|
00489A75 8B8310030000 mov eax, [ebx+$0310]
* Reference to: Controls.TControl.SetText(TControl;TCaption);
|
00489A7B E8F069FBFF call 00440470
....
...以下代码与前述类似,从略。
注意看00489A55 E8166AFBFF call 00440470 ;Controls.TControl.SetText(TControl;TCaption)这行,这个call是Delphi的标准函数调用,功能是设置控件显示的文字,按照Delphi的传值方式,EAX用于存放控件句柄,EDX用于存放赋值的字符串。用OllyDgb单步跟到00489A50 8B55FC mov edx, [ebp-$04]这行,发现寄存器EDX的值为"About AsfTools",很明显这里就是给标题设置显示内容的地方。我们往上看00489A30 B8089B4800 mov eax, $00489B08这行引用字符串pluvL}rK"gn~rI,然后经过3个相同call 004890F4得到明文串About AsfTools,跟入该call发现都是对字符串的一系列运算(因为我们不是破解,这里不祥述其内容了),由此可以断定call 004890F4即对密文解密的过程。现在有两种方法可以汉化该内容,一种是容易直接想到的,即分析解密算法找出它可逆的加密算法,然后编写一个加密字符串的程序,将汉化的字符串,如"关于 AsfTools"加密成密文并写回原程序;由于我们仅仅是为了汉化它,让他显示中文内容,我们可以用第二种方法,即修改程序代码,把不相干的解密部分全部Nop掉,令这里调用SetText之前的EDX为汉化字符串,强行让它显示我们需要的内容,当然这种方法对程序改动较大,比较暴力~
这里提供一种修改方案,利用OllyDbg或UltraEdit修改代码,将$00489B08处的密文替换为汉化后的字符串“关于 AsfTools”,改代码为mov edx,$00489B08将所有解密的代码nop掉,直接调用SetText,后面依次类推。这里有一点要注意的是“确定”按钮的文字长度超过了原来的“OK”长度,需要重新找个地址存放,我这里用了中间的一段空白地址$00489A42,你也可以使用其他地址或其他修改方法。修改后的代码如下:
引用:
00489A0C 55 push ebp
00489A0D 8BEC mov ebp, esp
00489A0F B904000000 mov ecx, $00000004
00489A14 6A00 push $00
00489A16 6A00 push $00
00489A18 49 dec ecx
00489A19 75F9 jnz 00489A14
00489A1B 51 push ecx
00489A1C 53 push ebx
00489A1D 8BD8 mov ebx, eax
00489A1F 33C0 xor eax, eax
00489A21 55 push ebp
* Possible String Reference to: '橹??脎?]?
|
00489A22 68F19A4800 push $00489AF1
***** TRY
|
00489A27 64FF30 push dword ptr fs:[eax]
00489A2A 648920 mov fs:[eax], esp
* Possible String Reference to: '关于 AsfTools '
|
00489A2D BA089B4800 mov edx, $00489B08
00489A32 EB1F jmp 00489A53
00489A34 90 nop
00489A35 90 nop
00489A36 90 nop
00489A37 90 nop
00489A38 0000 add [eax], al
00489A3A FFFF DB $FF, $FF //
00489A3C FFFF DB $FF, $FF //
00489A3E 05000000C8 add eax, -$38000000
00489A43 B7B6 mov bh, $B6
00489A45 A800 test al, $00
00489A47 0000 add [eax], al
00489A49 00FF add bh, bh
00489A4B FFFF DB $FF, $FF //
00489A4D FF00 inc dword ptr [eax]
00489A4F 0000 add [eax], al
00489A51 90 nop
00489A52 90 nop
00489A53 8BC3 mov eax, ebx
* Reference to: Controls.TControl.SetText(TControl;TCaption);
|
00489A55 E8166AFBFF call 00440470
* Possible String Reference to: '确定'
|
00489A5A BA429A4800 mov edx, $00489A42
00489A5F 90 nop
00489A60 90 nop
00489A61 90 nop
00489A62 90 nop
00489A63 90 nop
00489A64 90 nop
00489A65 90 nop
00489A66 90 nop
00489A67 90 nop
00489A68 90 nop
00489A69 90 nop
00489A6A 90 nop
00489A6B 90 nop
00489A6C 90 nop
00489A6D 90 nop
00489A6E 90 nop
00489A6F 90 nop
00489A70 90 nop
00489A71 90 nop
00489A72 90 nop
00489A73 90 nop
00489A74 90 nop
* Reference to control Button1 : TButton
|
00489A75 8B8310030000 mov eax, [ebx+$0310]
* Reference to: Controls.TControl.SetText(TControl;TCaption);
|
00489A7B E8F069FBFF call 00440470
....
...以下代码与前述类似,从略。
程序中还有几处类似的地方无法正常汉化,需要修改加密字符串,如SampleFrame中的内容,但是这部分内容与前面又有所不同,我们可以在资源中直接找到并汉化,只是运行时被重新SetText了而不能被显示,我们可以残忍的将这部分SetText代码统统Nop掉,该死的英文就不再显示了。注意一点,这边有个CheckBox的文本是动态显示的,不要把这个也Nop了,这个例外需要像上面About中的内容一样修改。
加密字符串搞定之后,发现还有未汉化的地方,查看资源Form发现剩下的都是以图片形式保存的,OK,将这些图片提取出来用任意图片编辑工具修改(我用Windows自带的画笔)成中文,然后将图片导回资源,运行一下,全部都变成熟悉可爱的中文了。搞定收工~!
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课