上次在这翻资料的时候正好看到某人写的虚拟村庄3的汉化教程 手头上正好也有这游戏 所以决定小试下汉化
+ ^- ?& {5 s: }* P" e$ I4 m9 \6 ~$ T4 G( h
在汉化前我们需要分析下游戏是如何显示字符串的 是贴图还是点阵
4 ^- Y) m( T* H# t这里是用bitblt贴上去的
' L- [% s8 j7 t+ n! y# e知道是贴图就要寻找相应的字库和字符串 # |" p' \9 u+ I7 ?3 F
字库在image文件夹就能找到
/ U" L" p3 ~) P- Y6 z* Q4 }& {字符串被压在了EXE里(脱壳后exe增大了3MB) 0 V6 i+ S2 F D0 n8 G$ h
$ G7 f- o8 x2 k- u' [ a# I& h/ S/ J
下面就是分析游戏是如何显示字符串的
6 y9 K, V, k' t用OD载入脱壳后的EXE文件 找到某个字符串下硬件访问 我这里断的是Quit) U) ~, {; r' v! `$ [) [
5 k) w2 G- u. R! `6 F按F9启动游戏- Z" A! m. d- s4 v. m% q$ F% e0 J p
然后断在4F24D2处
6 v" e5 a7 v- K: T- y9 F+ g P: J& c) G这里是读取字符串用的0 j! n* y6 f3 ?; j! E4 h& ~$ z/ I
9 C/ H" c; S" m# J- v2 l分析下
; n6 z3 f, U! Z1 E" ]! B004F24D0 |> 8B01 /MOV EAX,DWORD PTR DS:[ECX] 这里是读取4字节 quit1 h) `% p s+ z1 ?5 O( b1 {9 ~
004F24D2 |. |BA FFFEFE7E |MOV EDX,7EFEFEFF 这里一块主要分析字符串是否已经到\0- y0 h% x' c2 P1 y
004F24D7 |. |03D0 |ADD EDX,EAX
4 W3 w0 x& T. U4 z, r" e* k004F24D9 |. |83F0 FF |XOR EAX,FFFFFFFF1 g; H. c( T" M! O
004F24DC |. |33C2 |XOR EAX,EDX# v% q4 v' g: ]# V& L' X( P; K' @
004F24DE |. |83C1 04 |ADD ECX,4 读取后面4个字节1 U- W& _/ {1 w
004F24E1 |. |A9 00010181 |TEST EAX,81010100 9 {* k0 Z/ S2 G3 ?
004F24E6 |.^ 74 E8 |JE SHORT Unpacked.004F24D0 如果是4个00(也就是81010100)就跳出
+ b7 ~6 M: W) G* `; P$ t% D- n/ ], U5 ^8 W7 E; m0 u9 [
这里要注意一下/ s6 N1 T. r' v" ~! R) E' Y
因为是4字节一取 \0处一定要是00 00 00 00
7 E! a0 A$ K9 t; F如果要把Quit
' \. F* {: P6 B4 r) p; {: c+ Q* d% Q" E' k51 75 69 74 00 00 00 00 Quit....Quit....* `8 S3 U; t: a
翻译成"退出吧" 就需要在加4字节
& T: r+ E: E% C" d4 t地方不够用咋办 幸好ecx是个指针 MOV EAX,DWORD PTR DS:[ECX]( \& \" n2 H0 z. z1 e. I
只要把ecx里的地址改成你的就OK了
( v6 ^9 X6 O0 f; ^5 A; N
# r: @+ ?! P6 P( D6 ?! k继续找处理图片的地方9 A* g% a+ U( e9 } L* e
一路跟下来到了
* j7 _2 K4 C; M) Q ( x+ t% ^8 k) e7 ^3 ~+ H; Y
004F398C |. 83E6 F0 AND ESI,FFFFFFF0
) Q3 c& e3 x) v! h004F398F |> 56 PUSH ESI ; /HeapSize = 5
4 z" w9 {' |( M! b7 ?4 n004F3990 |. 6A 00 PUSH 0 ; |Flags = 0* J& z6 i2 M) y0 B. ~7 g
004F3992 |. FF35 3C7B7B00 PUSH DWORD PTR DS:[7B7B3C] ; |hHeap = 00D60000! U" T* l, {: k
004F3998 |. FF15 14815100 CALL DWORD PTR DS:[<&kernel32.HeapAlloc>>; \HeapAlloc. V0 r5 T6 }5 M- }
004F399E |> 5E POP ESI: m0 W7 Q2 s+ k
+ f6 s1 X; F e$ Y
发现HeapAlloc 这个是用来分配内存的& q6 x2 w, _% s
F8步过 取eax的地址 就是将写入新的quit的地方6 h, K, s: |) f, @# d8 X6 w
对其下硬件访问 F9运行
- K7 z% B) `) a0 G1 L断在了403811" \. V* K2 \$ k* Y4 B" v# ~
在F9几次 断在了4091c41 V+ H3 A9 A% [. X' P a
在F9几次 回到了403811
; ~ h8 A e" f. l) N8 b9 ]
1 g8 |3 P! r8 ]1 R2 N) w D# ]确定就是这2处地方了4 Z8 b- V a; f* `- g
这里我选择了4091c4 因为在跟踪403811后发现这里的数据没用
( K' S q- e7 V4 u I N, `# @. ?$ W+ Y1 M6 _' H3 M
004091BE |> 8B55 08 /MOV EDX,DWORD PTR SS:[EBP+8]
2 L2 e7 D& Y! A W004091C1 |. |0FBE02 |MOVSX EAX,BYTE PTR DS:[EDX] 取第一个字节Q& n# X Y2 Q& T+ u- b
004091C4 |. |85C0 |TEST EAX,EAX
9 U. A9 x4 u7 E. x' [$ f004091C6 |. |0F84 E2000000 |JE Unpacked.004092AE 字符串到达\0就跳出
y2 ?* U% v/ m004091CC |. |8B4D 08 |MOV ECX,DWORD PTR SS:[EBP+8]
9 f0 \' o, {2 Y004091CF |. |0FBE11 |MOVSX EDX,BYTE PTR DS:[ECX] 取第一个字节Q; \% a. g& ]* ?# Y) p3 k
004091D2 |. |83FA 0A |CMP EDX,0A 判断是否是空格
% }% }# E! O0 H4 C( y% c- u004091D5 |. |75 21 |JNZ SHORT Unpacked.004091F8
& o6 v7 {$ ^: V1 ^; S, E H; s" g004091D7 |. |8B45 E8 |MOV EAX,DWORD PTR SS:[EBP-18]6 H" w+ P$ ~* b5 W6 a( z8 f9 a
004091DA |. |8945 0C |MOV DWORD PTR SS:[EBP+C],EAX$ e: C5 t5 j! T; Y* ~8 u
004091DD |. |6A 00 |PUSH 0 ; /Arg1 = 00000000 [: R9 V }1 u. O8 _& a; g M
004091DF |. |8B4D F8 |MOV ECX,DWORD PTR SS:[EBP-8] ; |
; E- o( z) p2 f% [004091E2 |. |E8 C9A7FFFF |CALL Unpacked.004039B0 ; \Unpacked.004039B0; Z* _$ N) Q! F" a2 l3 n- c
004091E7 |. |0345 10 |ADD EAX,DWORD PTR SS:[EBP+10]7 F! d; a/ Z- I
004091EA |. |8945 10 |MOV DWORD PTR SS:[EBP+10],EAX8 ?* R6 Y/ X% P% b. J% u
004091ED |. |8B4D 08 |MOV ECX,DWORD PTR SS:[EBP+8]5 V! s! p/ q- v' _3 _/ @& O
004091F0 |. |83C1 01 |ADD ECX,1
! C; M4 O, g7 T$ H, }% C004091F3 |. |894D 08 |MOV DWORD PTR SS:[EBP+8],ECX+ w8 w0 G5 {9 {' q# n
004091F6 |.^ EB C6 |JMP SHORT Unpacked.004091BE
1 c# ]5 M+ A: L c004091F8 |> |8B55 08 |MOV EDX,DWORD PTR SS:[EBP+8] 不是的空格跳到这里
9 I3 ^8 y8 L, O0 Z: U* Z" O004091FB |. |0FBE02 |MOVSX EAX,BYTE PTR DS:[EDX] 把Q给EAX (实现双字节 就要让他取WORD 这里需要改造)
n8 v. F( s3 e% z004091FE |. |8945 C0 |MOV DWORD PTR SS:[EBP-40],EAX 把Q 放到参数中去' P/ C% m( M5 R
00409201 |. |8D4D D8 |LEA ECX,DWORD PTR SS:[EBP-28]9 M& {* R& ^7 A% C$ I
00409204 |. |51 |PUSH ECX ; /Arg2
- u' c0 z) \6 L5 c) ^* `00409205 |. |8B55 C0 |MOV EDX,DWORD PTR SS:[EBP-40] ; |; \- j, {' x5 e" h% h
00409208 |. |52 |PUSH EDX ; |Arg1 压入Q& ?- X0 D3 {% b% Z2 M
00409209 |. |8B4D F8 |MOV ECX,DWORD PTR SS:[EBP-8] ; |+ ?+ z p7 u) k; S+ p" a
0040920C |. |E8 0FB4FFFF |CALL Unpacked.00404620 ; \Unpacked.00404620 这里是关键
3 ]3 |, X4 C( \ ?% J! i- y00409211 |. |8B45 08 |MOV EAX,DWORD PTR SS:[EBP+8]
! \* l5 x @: ~$ \3 i9 R! z* G& F) Q00409214 |. |83C0 01 |ADD EAX,1 读完Q后读u: U, n* M$ o+ v( Z( Z" @" ~
00409217 |. |8945 08 |MOV DWORD PTR SS:[EBP+8],EAX) v7 v3 K" C2 {8 \- P' C: G
0040921A |. |8D4D D8 |LEA ECX,DWORD PTR SS:[EBP-28]* X+ p8 I: i: D2 _8 r6 a& R& Q% ~
0040921D |. |E8 5E8BFFFF |CALL Unpacked.00401D80 这里存入了画Q需要的长度) R$ G) G: X/ a3 P& o# `
00409222 |. |8945 D4 |MOV DWORD PTR SS:[EBP-2C],EAX* s0 c+ ]! W- G! g- i, a5 z
00409225 |. |837D D4 00 |CMP DWORD PTR SS:[EBP-2C],0
* B+ r. t: w3 \) a0 ~00409229 |. |74 7E |JE SHORT Unpacked.004092A9
$ x" @) R! ?) e8 w% d
" g4 J: }- r( a# O6 o" i, l3 I. C4 e% V
6 [ x4 r0 E/ K" f
( f' ^# {, `2 J; W7 a
2 H+ m7 l: ?% F( o' W0 s0 Y# x
* ^3 o3 ~. a2 Q9 H# L00404620 /$ 55 PUSH EBP4 C" D) q& h' m! S8 k& V
00404621 |. 8BEC MOV EBP,ESP' {3 U; S, ^5 Q0 U2 z' X
00404623 |. 83EC 0C SUB ESP,0C
9 P2 X+ l! R# j1 ~00404626 |. 894D F4 MOV DWORD PTR SS:[EBP-C],ECX
+ |" o f9 t: v/ b% A2 B+ R00404629 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]. C# K/ i& Y8 Z" q: c# f
0040462C |. 8B48 14 MOV ECX,DWORD PTR DS:[EAX+14]
. T* K# ]0 A7 N9 G; e+ V0040462F |. 894D FC MOV DWORD PTR SS:[EBP-4],ECX
/ Y) _7 x2 U y8 z# W; p00404632 |. 837D 08 00 CMP DWORD PTR SS:[EBP+8],0 这里就是边界检查$ N9 i V# x- [; r
00404636 |. 7D 0D JGE SHORT Unpacked.00404645' t0 d7 K) ?% s# h/ p% J
00404638 |. 8A55 08 MOV DL,BYTE PTR SS:[EBP+8]
' }4 W! k2 z' I7 h# F0040463B |. 8855 FB MOV BYTE PTR SS:[EBP-5],DL4 Y% s5 B& q5 e3 j/ r
0040463E |. 0FB645 FB MOVZX EAX,BYTE PTR SS:[EBP-5]5 L; ?1 ] m. y) e
00404642 |. 8945 08 MOV DWORD PTR SS:[EBP+8],EAX
+ [; _5 q7 W% F4 j2 ~- Z. `. f00404645 |> 817D 08 00010>CMP DWORD PTR SS:[EBP+8],100 边界检查
% o; U+ u' M: b0040464C |. 7D 18 JGE SHORT Unpacked.00404666( P# N( L! V8 `0 _) t
0040464E |. 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+8]8 v. N( P# Y3 q5 @: h5 y' [
00404651 |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]6 s' j, N: @. |" e3 q/ u- k, ]
00404654 |. 8B448A 18 MOV EAX,DWORD PTR DS:[EDX+ECX*4+18]: f8 g% `% ^$ D' M# H
00404658 |. 6BC0 14 IMUL EAX,EAX,14
9 C5 d/ S% p R X* t0 Y' Q. R0040465B |. 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-C]% m4 |5 `( T4 G' f% [) x
0040465E |. 0341 14 ADD EAX,DWORD PTR DS:[ECX+14]
* i7 g4 @5 O y% p6 a5 O00404661 |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX
! j" Z/ M" e, j3 d8 i+ t5 V00404664 |. EB 15 JMP SHORT Unpacked.0040467B
& t# ~; k" x# n8 O0 }& `00404666 |> 8B55 08 MOV EDX,DWORD PTR SS:[EBP+8] 这里一块是算Q的码表
( l: d9 s0 U) D! A, j9 S& F
/ @1 N8 C# v* f! Q! k# s& R
/ e k6 i3 k: h( l' ?% f, C
5 E: Q# p6 t, i2 |7 U1 ]6 H0054AA48 51 00 00 00 2D 02 00 00 00 00 00 00 3C 02 00 00 Q...-......<..! E8 w8 C" q2 h# C2 L: e
0054AA58 1B 00 00 00 ...
. Q# y# Y9 W- F" ^0 e$ I
' t0 f2 k5 j! M( X. } D* |51就是字符Q2 \) K" F9 {5 B- d1 K: _. F7 I
2D 02 00 00
( F5 a# C8 }# u4 k0 F00 00 00 00
0 F! _! _ W8 ?- U2 \5 @9 d9 v3C 02 00 00
: e7 f8 Q1 v5 o% N$ h1B 00 00 00/ ~: w. k8 }$ I+ L! d% ~
+ [ j1 _7 u) w( q- ~* r3 M- G A━━┓
; z! l' m3 u- W+ P ┃ Q ┃ " E2 ]( O$ E, z) f9 @# _
┗━━B* `7 Q1 _( Q1 ]% z3 V. B2 [9 X. w
. ?! B# m! ?8 {' b4 m5 g6 o* L$ WA的坐标 (22D,0)
2 ?4 ]$ T8 }8 NB的坐标 (23C,1B)
2 Z6 r( b- e7 x
: Q) K$ y" k; u! t* U
3 K+ G/ V% c" R( C8 P. n- t0 |; @$ \: I, ?7 U& E# F
00404669 |. 81E2 FF7F0000 AND EDX,7FFF. y' G E0 l: S) A" D
0040466F |. 6BD2 14 IMUL EDX,EDX,145 I8 X# ?& z6 ?
00404672 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
( R/ Z2 `; `6 V* P; d1 U/ a/ e9 S S4 \00404675 |. 0350 14 ADD EDX,DWORD PTR DS:[EAX+14]
1 }1 L' A+ X: b4 \& R7 L" x0 [00404678 |. 8955 FC MOV DWORD PTR SS:[EBP-4],EDX
; A1 d) V; |% H0040467B |> 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]
0 m$ x7 v' Y+ Q; M6 C1 C0040467E |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]- k# e$ b8 i' I% s$ F2 V
00404681 |. 8B42 04 MOV EAX,DWORD PTR DS:[EDX+4]
' q z/ Z0 k% r, _00404684 |. 8901 MOV DWORD PTR DS:[ECX],EAX 存入22D3 u \/ |4 O; ?! I5 W7 b
00404686 |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]% f- } m4 M# a' |5 ]' Y
00404689 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]$ X& S6 _4 k' O: ^
0040468C |. 8B42 0C MOV EAX,DWORD PTR DS:[EDX+C]
$ b* x1 m5 o# |7 {! s0040468F |. 8941 08 MOV DWORD PTR DS:[ECX+8],EAX 存入23C% U0 M: M6 P& L% v' _1 m4 {! }
00404692 |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]) N% g: v1 g1 O2 c+ f0 D [" n
00404695 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
" N9 ]% _: q a" ^5 _# O! m00404698 |. 8B42 08 MOV EAX,DWORD PTR DS:[EDX+8]
' V: w/ s h4 ~2 b, m4 |: j0040469B |. 8941 04 MOV DWORD PTR DS:[ECX+4],EAX 存入0' M3 n- q4 x7 [* v6 I: ^
0040469E |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]
8 `, v5 m' _+ D% q004046A1 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
2 ?' @ M0 k( I( l6 n004046A4 |. 8B42 10 MOV EAX,DWORD PTR DS:[EDX+10], I8 X% a$ |8 x) n& q' h
004046A7 |. 8941 0C MOV DWORD PTR DS:[ECX+C],EAX 存入1B' [9 ~* R* {# s. ]1 M; m9 M# ], v$ h
004046AA |. 8BE5 MOV ESP,EBP+ i: T% \% j: ?# F, J6 p* c1 [; y% O
004046AC |. 5D POP EBP
) ^% A% @ g/ L004046AD \. C2 0800 RETN 8 i/ l j0 V, B/ m; A/ Y* H
9 C( y9 s: J. p4 z" G0 W% A+ H1 x9 M3 K- C4 \- M" t+ @
3 d& s0 n2 P% g: f; J: }' \
( ?- j6 w; X7 f! ^- P0 F" T
$ V8 u3 e; A+ k- ]3 r知道这些后 就可以改造了) E2 R- |( k. L! B3 j
先改字库( I+ Q+ E3 s) L6 E& P$ m. j
6 M6 k* I7 Z% y s! h2 w* n: K* P. z/ I: Z. O. _
然后改成支持汉字的
: U9 R& H/ `8 ~$ ^1 `9 b2 ]+ y) m2 }# ^把4091d2 的 CMP EDX,0A 改成jmp* t& J6 R3 j/ L; x: e
跳到我的代码上去( ^- r3 ^, W) }
8 }7 Y5 p& I/ E0 P' [AND EDX,0FF 去除高位的FF
! D$ P# ]) c8 E8 a4 D& s3 XCMP EDX,0B0 比较是否汉字 跟比较80一样 因为我的字库是从 啊(B0 A1) 开始的/ N ` U- G' ?2 f$ D4 T) q
JL Unpacked.004091F8 小于 B0的就跳回去
% C3 h$ ^+ @+ I& d+ A( IMOV EDX,DWORD PTR SS:[EBP+8]
$ J' O9 Y9 i c0 n4 lMOVSX EAX,WORD PTR DS:[EDX] 取2个字节 (支持汉字)8 _3 R( u( t! H
AND EAX,0FFFF 去除汉字高位的FF; g1 ]( e2 I- c. e- e* ]/ \
MOV DWORD PTR SS:[EBP-40],EAX 存入形参
" H3 m: _# x$ TLEA ECX,DWORD PTR SS:[EBP-28]
2 T1 @+ ?1 a1 v. c9 VPUSH ECX ; /Arg2
3 q A: x; b9 y' {1 cMOV EDX,DWORD PTR SS:[EBP-40] ; |8 j. [+ G7 F% Q* r7 E
PUSH EDX ; |Arg1
/ [' |& U/ i- k: [4 zMOV ECX,DWORD PTR SS:[EBP-8] ; |# Z& [7 N2 y2 Z, y9 }$ ^$ h
CALL Unpacked.007CFF3C 这里是读取并存入 字符串X Y坐标8 W: a X7 l! O; O+ n" v- u' t U
MOV EAX,DWORD PTR SS:[EBP+8]
" \" b& U! m# @4 I$ k/ pADD EAX,2 call出来后加2个字节
T& ^- ?: L% ` J1 Q" z) dJMP Unpacked.00409217, j# C! ?, {" x5 R
& ^+ p# P$ H: v9 Y6 r0 ?
! p5 Q* D& x9 K! h! `& |2 q
3 C! k9 L! Z; \# [4 p
1 n3 Q8 y. v5 ~: z1 u: fPUSH EBP
9 e$ g3 g# e gMOV EBP,ESP
" i; z' g' f% @/ T/ J& n# B$ qSUB ESP,0C
' I) C" G6 H ]( I) S. S7 wMOV DWORD PTR SS:[EBP-C],ECX- P/ |. j* T) v2 s, n. ?5 t/ \
MOV EAX,DWORD PTR SS:[EBP-C]( V- c8 e+ C* t
MOV ECX,DWORD PTR DS:[EAX+14]4 K0 }! g: ^5 y2 l- J
MOV DWORD PTR SS:[EBP-4],ECX
- K, V% A7 z! z$ wCMP DWORD PTR SS:[EBP+8],0F9D7 边界检查 我这里最后个文字是 座(D7 F9)
1 E% ^, |# n& |/ T ]- l3 ~JG SHORT Unpacked.007CFF8E 超出就绘制一个空白图片! ?- \. ~/ v& n4 }
MOV ECX,DWORD PTR SS:[EBP+8] 从形参读取汉字 把汉字 放入ecx (我这里代码写的乱)6 R3 ~5 L+ `! s8 S; {
XOR EAX,EAX# W3 Q- O% ?1 C
MOV AL,CL 把汉字第一个字节 放入eax
: O3 F7 H- D9 r" e; n/ W* C! @SHR CX,8 右移8位取第二个字节
& }" ?* m0 P B) }1 hXOR EDX,EDX
! W+ A0 Q$ f b8 n5 C+ q+ [MOV DL,CL 把第2个字节放到edx去; V& {" q4 [0 D4 E* x+ T/ S
SUB AL,0B0 这里是我自己写的算法 不用再读取码表了, K, x }6 d; ]. h6 d& Y$ ?' t
SUB DL,0A1* }& A6 P( y& \0 n2 R- w _& W$ A
IMUL EAX,EAX,10 我用的 宋体16 一个汉字是16X161 x0 Q @& P b E7 J+ ^
IMUL EDX,EDX,10! X: D, s" i: h# ?3 C6 b
ADD EAX,20 加上我图片原来的高度& y% q: H' E4 | { i
MOV ECX,DWORD PTR SS:[EBP+C]
x& @% d1 n( Y0 n9 L1 p% K& AMOV DWORD PTR DS:[ECX],EDX- c1 o$ l ]' l3 Z* w) |
MOV DWORD PTR DS:[ECX+4],EAX" ]: p% c6 a% n$ R
ADD EAX,10% k" @/ { i& y" `) a7 m
ADD EDX,10
0 ?1 s" ]6 l- [( ] J, K* I* `/ u4 OMOV DWORD PTR DS:[ECX+8],EDX* k/ U* m( `: V5 q3 n, l. i8 e/ m
MOV DWORD PTR DS:[ECX+C],EAX
$ K2 [$ L$ z# qMOV ESP,EBP
- S. d* l, K" a5 Z: h* B# PPOP EBP l4 a" K; u: x& Y5 D3 B+ o) W
RETN 8
+ E9 G8 r" e( o1 r0 C
4 b! k2 v2 Q* y& g# L7 b' z
( S( G6 Y, r+ W6 v1 T |