上次在这翻资料的时候正好看到某人写的虚拟村庄3的汉化教程 手头上正好也有这游戏 所以决定小试下汉化 5 S4 h; x9 n9 ~1 w9 ~5 K
) ~% e; L- w% X2 d! {在汉化前我们需要分析下游戏是如何显示字符串的 是贴图还是点阵 2 G0 ?8 x1 o. o$ [& @& T( o: x
这里是用bitblt贴上去的 " o0 p0 i' _0 D0 {, k6 K
知道是贴图就要寻找相应的字库和字符串 + O) d4 v# e3 j
字库在image文件夹就能找到
" C( Y* r6 {$ y7 m* g. f字符串被压在了EXE里(脱壳后exe增大了3MB)
, }# {! a; Q5 K& K, G" D0 r. ^6 E/ g: x, T# Z/ A4 H8 [% Z
下面就是分析游戏是如何显示字符串的
. g2 X% D$ y L' F O用OD载入脱壳后的EXE文件 找到某个字符串下硬件访问 我这里断的是Quit R6 \. r1 V- D; [" O
K; f' Q8 H' u ?: J按F9启动游戏( [5 ?& Z7 M& o
然后断在4F24D2处
0 V i. U! W. W( v7 ]' y这里是读取字符串用的0 j; n0 [: h# r! m
7 w7 S( j. ^/ X# `0 X
分析下& C5 V" M1 R! }+ z+ \
004F24D0 |> 8B01 /MOV EAX,DWORD PTR DS:[ECX] 这里是读取4字节 quit
. V" n( y5 f8 u( y }$ F004F24D2 |. |BA FFFEFE7E |MOV EDX,7EFEFEFF 这里一块主要分析字符串是否已经到\0# d3 X. N: C( S
004F24D7 |. |03D0 |ADD EDX,EAX
, _ H1 K. R, U& ~. w004F24D9 |. |83F0 FF |XOR EAX,FFFFFFFF* I; _9 S# A9 Q' X& A& K
004F24DC |. |33C2 |XOR EAX,EDX
5 t( e3 n8 B: b0 N& Q: |004F24DE |. |83C1 04 |ADD ECX,4 读取后面4个字节
; v9 ^& u" v" q$ ]8 `& _004F24E1 |. |A9 00010181 |TEST EAX,81010100
( k3 H1 h1 V- X8 {004F24E6 |.^ 74 E8 |JE SHORT Unpacked.004F24D0 如果是4个00(也就是81010100)就跳出
0 r( f3 L/ G3 I2 V1 Q* N' H! I, i8 a$ l
这里要注意一下" J, O7 F, x4 [& h) L
因为是4字节一取 \0处一定要是00 00 00 00
5 E; l% h( X( Y* n如果要把Quit
3 k6 R3 V( u% t51 75 69 74 00 00 00 00 Quit....Quit....
& A+ d8 F# G: E& f9 ]# ^翻译成"退出吧" 就需要在加4字节* `& T. Q0 n! ^7 U, w
地方不够用咋办 幸好ecx是个指针 MOV EAX,DWORD PTR DS:[ECX]
8 A% p/ n0 ? ~1 V6 g) A% S只要把ecx里的地址改成你的就OK了
- y! I, @7 d9 J# }
' W/ i0 J- i' T. ~4 r/ L继续找处理图片的地方; @6 v2 t1 U( Y9 Z" T+ M. z
一路跟下来到了) Y+ j9 L0 v. ~. Q0 N `$ z3 T
% Z! M. D) r8 P6 S8 E" T004F398C |. 83E6 F0 AND ESI,FFFFFFF0- |- L: |% P5 Y( L# ~. z7 C
004F398F |> 56 PUSH ESI ; /HeapSize = 5
9 o3 }! p8 d" v- J; f) S) m o004F3990 |. 6A 00 PUSH 0 ; |Flags = 0
3 e$ u. E. \% m0 t7 S004F3992 |. FF35 3C7B7B00 PUSH DWORD PTR DS:[7B7B3C] ; |hHeap = 00D60000
" J& {+ p! S1 J8 H9 P7 k8 f2 s004F3998 |. FF15 14815100 CALL DWORD PTR DS:[<&kernel32.HeapAlloc>>; \HeapAlloc: c/ t3 F- @0 @, I
004F399E |> 5E POP ESI' G! N* s f' w+ G
, O) U4 V9 w6 X0 k. e3 E) }' s8 g3 u) ^
发现HeapAlloc 这个是用来分配内存的+ F0 Z9 U+ H% B3 Y: m+ a
F8步过 取eax的地址 就是将写入新的quit的地方
3 K; h4 L, \( Z$ R8 x对其下硬件访问 F9运行& A& i* V- X) @) t; [4 T
断在了403811) Q. d6 E m# A* f/ b0 l
在F9几次 断在了4091c47 u7 B5 p2 ^" X2 b, W. p
在F9几次 回到了403811
0 T5 t( Q6 `9 H l& d
: W" P: i. q0 X0 g- h0 `确定就是这2处地方了
- P. |/ j5 }( O; L2 r这里我选择了4091c4 因为在跟踪403811后发现这里的数据没用' T1 x1 X5 P) l9 d" a- E2 \
D+ M' ^. T! y8 r" N8 D2 B5 x004091BE |> 8B55 08 /MOV EDX,DWORD PTR SS:[EBP+8]% r, ], y1 Z3 J) \3 {
004091C1 |. |0FBE02 |MOVSX EAX,BYTE PTR DS:[EDX] 取第一个字节Q' l3 @' `( e& ^
004091C4 |. |85C0 |TEST EAX,EAX 5 y/ e4 U! v( o3 I
004091C6 |. |0F84 E2000000 |JE Unpacked.004092AE 字符串到达\0就跳出
2 R0 m+ p, D9 |! f% d Q004091CC |. |8B4D 08 |MOV ECX,DWORD PTR SS:[EBP+8]) H2 t3 ^; U0 d1 \& v; H
004091CF |. |0FBE11 |MOVSX EDX,BYTE PTR DS:[ECX] 取第一个字节Q# S7 F) h1 g- p2 h' w! n" H2 U
004091D2 |. |83FA 0A |CMP EDX,0A 判断是否是空格
, W: `+ S+ E/ _- g004091D5 |. |75 21 |JNZ SHORT Unpacked.004091F83 z0 |6 |! `- D, L
004091D7 |. |8B45 E8 |MOV EAX,DWORD PTR SS:[EBP-18]& J; ]$ D, c& U5 q; {
004091DA |. |8945 0C |MOV DWORD PTR SS:[EBP+C],EAX
; L% e" Y$ c( b' n% g0 u0 |004091DD |. |6A 00 |PUSH 0 ; /Arg1 = 00000000
/ Z. z$ y" g. e7 E' Y9 y004091DF |. |8B4D F8 |MOV ECX,DWORD PTR SS:[EBP-8] ; |. @( n4 @& }, v0 J4 Z5 G
004091E2 |. |E8 C9A7FFFF |CALL Unpacked.004039B0 ; \Unpacked.004039B0
# {* c2 @) H, Y6 l/ b B/ X004091E7 |. |0345 10 |ADD EAX,DWORD PTR SS:[EBP+10]
2 L- E4 U1 I- T1 n004091EA |. |8945 10 |MOV DWORD PTR SS:[EBP+10],EAX& I$ }9 K2 a. F: O/ o& w/ E, e
004091ED |. |8B4D 08 |MOV ECX,DWORD PTR SS:[EBP+8]; Q, Q# K1 u. j8 ~
004091F0 |. |83C1 01 |ADD ECX,1
1 C% x8 o, {( R004091F3 |. |894D 08 |MOV DWORD PTR SS:[EBP+8],ECX% t' C/ Y7 n8 S) g* k
004091F6 |.^ EB C6 |JMP SHORT Unpacked.004091BE! K- C4 P9 }) j: s$ ^" D
004091F8 |> |8B55 08 |MOV EDX,DWORD PTR SS:[EBP+8] 不是的空格跳到这里
& `' M, @, {; g$ M' B004091FB |. |0FBE02 |MOVSX EAX,BYTE PTR DS:[EDX] 把Q给EAX (实现双字节 就要让他取WORD 这里需要改造)( D8 S% r3 t6 o; f) P7 G, s7 }
004091FE |. |8945 C0 |MOV DWORD PTR SS:[EBP-40],EAX 把Q 放到参数中去" D9 k7 C; H7 I' d: V5 n+ ?( |# Q* U$ K
00409201 |. |8D4D D8 |LEA ECX,DWORD PTR SS:[EBP-28]% I0 G: Q" a' g
00409204 |. |51 |PUSH ECX ; /Arg2
( P9 M) C6 Q O0 f$ r00409205 |. |8B55 C0 |MOV EDX,DWORD PTR SS:[EBP-40] ; |
|3 F, |$ z" v4 ^00409208 |. |52 |PUSH EDX ; |Arg1 压入Q
& P0 b' p+ c' c& C4 K% Z. m) B00409209 |. |8B4D F8 |MOV ECX,DWORD PTR SS:[EBP-8] ; |+ q5 f6 T. _* _. k
0040920C |. |E8 0FB4FFFF |CALL Unpacked.00404620 ; \Unpacked.00404620 这里是关键+ ?. q5 T+ }7 P: T
00409211 |. |8B45 08 |MOV EAX,DWORD PTR SS:[EBP+8]
% R1 B# f1 b$ {00409214 |. |83C0 01 |ADD EAX,1 读完Q后读u
# v4 l6 ^* Y3 a7 L4 s00409217 |. |8945 08 |MOV DWORD PTR SS:[EBP+8],EAX5 S" @! V! d9 n' C- b7 w3 @: O/ d/ T! w
0040921A |. |8D4D D8 |LEA ECX,DWORD PTR SS:[EBP-28]
% ^3 n2 d* N4 @1 g/ U0 e3 R4 n- [0040921D |. |E8 5E8BFFFF |CALL Unpacked.00401D80 这里存入了画Q需要的长度- u& [# w# G- |3 ^
00409222 |. |8945 D4 |MOV DWORD PTR SS:[EBP-2C],EAX$ h. Q1 ?" X2 Q7 [0 W0 {" ~/ d
00409225 |. |837D D4 00 |CMP DWORD PTR SS:[EBP-2C],0
$ j3 k3 H/ p5 l. H& j; D00409229 |. |74 7E |JE SHORT Unpacked.004092A97 B* g9 F6 f2 f, S K
V: T! n+ \/ i( e6 b6 B$ B. S
! L, I, _9 T* W5 L; U& D3 W8 Q0 p% L' O! K, z8 J$ x
" ?+ l$ @3 S( d8 I. J8 u% t+ y
1 w) K- _9 s% c6 M Z* r4 f( d" g J% \3 [# C2 W+ K
00404620 /$ 55 PUSH EBP
& _; H8 E& R6 D2 T00404621 |. 8BEC MOV EBP,ESP
# f! S2 E5 h* q/ Y00404623 |. 83EC 0C SUB ESP,0C3 z C9 G$ W2 O1 j1 |7 Q* u
00404626 |. 894D F4 MOV DWORD PTR SS:[EBP-C],ECX
- d( ~& X" X+ u0 o$ O00404629 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]! \2 w7 Y% o: M0 j& Z R
0040462C |. 8B48 14 MOV ECX,DWORD PTR DS:[EAX+14]
' [( x* x* _8 a" L8 ]0 H0040462F |. 894D FC MOV DWORD PTR SS:[EBP-4],ECX$ t( l8 I' \4 l' J& Q* ?
00404632 |. 837D 08 00 CMP DWORD PTR SS:[EBP+8],0 这里就是边界检查
0 F3 K4 X- a# L1 M7 z# q00404636 |. 7D 0D JGE SHORT Unpacked.00404645
# E; G, f% R# b: O1 v00404638 |. 8A55 08 MOV DL,BYTE PTR SS:[EBP+8]7 r5 Z5 a. _0 G+ f- B# }3 f% ^+ k5 }
0040463B |. 8855 FB MOV BYTE PTR SS:[EBP-5],DL
5 u) n& _" ]& x( Y0040463E |. 0FB645 FB MOVZX EAX,BYTE PTR SS:[EBP-5]1 i" s: @, C) ~: I- X' c4 Z! D5 J
00404642 |. 8945 08 MOV DWORD PTR SS:[EBP+8],EAX- v/ p, ?4 _/ `# J! r! W/ v b
00404645 |> 817D 08 00010>CMP DWORD PTR SS:[EBP+8],100 边界检查
6 f+ h9 t& P* S9 Y0040464C |. 7D 18 JGE SHORT Unpacked.00404666
" i# `. p2 E3 a" o$ Z& C% ~0040464E |. 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+8]
5 l5 Z8 F9 R& ~7 a; K+ {: C00404651 |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]& r$ P; Q9 G6 ]( {% m
00404654 |. 8B448A 18 MOV EAX,DWORD PTR DS:[EDX+ECX*4+18]) s% m4 _3 L/ x$ C) Z$ ?
00404658 |. 6BC0 14 IMUL EAX,EAX,14( T8 g, w0 W) W d+ ]8 ~
0040465B |. 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-C]
0 d9 F! J9 r4 h6 }0040465E |. 0341 14 ADD EAX,DWORD PTR DS:[ECX+14]
. q; u, c( D% M- u* A00404661 |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX' v- J. w" g! }, A$ B
00404664 |. EB 15 JMP SHORT Unpacked.0040467B. u; I: ]( _% b9 i& X# i% H2 ?3 Q, D
00404666 |> 8B55 08 MOV EDX,DWORD PTR SS:[EBP+8] 这里一块是算Q的码表! |# B, h; m) n t8 I5 ~
+ y3 v' j, U! x2 ^7 D& W+ Y, b' _/ o; q6 O. Z# m. E( U
! L* K- e7 S9 X0054AA48 51 00 00 00 2D 02 00 00 00 00 00 00 3C 02 00 00 Q...-......<..! y l/ Y& f$ o8 Q
0054AA58 1B 00 00 00 ...
; ?0 U5 i7 w, F* o1 t, n. p6 }) A7 `+ q+ L3 H# @/ p5 r
51就是字符Q
3 ^+ A* O1 a1 x& I, q2D 02 00 00
# N4 M7 v% w% \1 I, X- {00 00 00 00) ^3 r' e* r4 Y
3C 02 00 008 a4 b8 c* e1 o+ k% {% Z
1B 00 00 00! F d' f2 @/ x( U+ B7 }
+ T4 C2 Z0 t- \7 |- |- M( o) }
A━━┓
' f2 `0 N' K0 z, i6 `$ v ┃ Q ┃ % I* [& Y. [6 |0 g
┗━━B
) u [$ P( v0 g* `+ R# J) [. r3 [* ~) Z
A的坐标 (22D,0)& Y% e6 @/ v8 `7 i) z* C* f
B的坐标 (23C,1B)
7 p5 S/ J$ x- O0 E& N* Q/ ?+ @+ ~. h- f) |- ~
" ?( W6 A& l# C' N* y3 f1 _1 u" U& Y7 B. F3 ]% }4 x
00404669 |. 81E2 FF7F0000 AND EDX,7FFF
+ ?4 L7 H) o/ A4 O0040466F |. 6BD2 14 IMUL EDX,EDX,14
1 H6 b; V, y1 b7 U00404672 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]4 r- v& |6 c( a D' K; `# a, G. D
00404675 |. 0350 14 ADD EDX,DWORD PTR DS:[EAX+14]8 R0 f' C( k1 m' m& z
00404678 |. 8955 FC MOV DWORD PTR SS:[EBP-4],EDX8 ^. p! N5 A/ s" R" W% @( i
0040467B |> 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]$ W* P0 }& ]5 r% J0 d0 G
0040467E |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
) p, X& U( ~1 W- [& Q7 g00404681 |. 8B42 04 MOV EAX,DWORD PTR DS:[EDX+4]( Q0 j: V# ~1 [; ^; q
00404684 |. 8901 MOV DWORD PTR DS:[ECX],EAX 存入22D
7 |0 |4 Y5 ^9 s1 |% R; U s5 |00404686 |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]
. a+ v9 D) p) Z5 c& o) Q2 r" ?00404689 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]+ Z; y' F' P' [$ H
0040468C |. 8B42 0C MOV EAX,DWORD PTR DS:[EDX+C]1 t! l) h* T. M I
0040468F |. 8941 08 MOV DWORD PTR DS:[ECX+8],EAX 存入23C' i5 \& |$ W* p6 G# D1 E5 q
00404692 |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]
& t3 M w: N5 A7 c/ M6 b00404695 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]( @1 H: @- U* x4 ~ @
00404698 |. 8B42 08 MOV EAX,DWORD PTR DS:[EDX+8]& `0 h/ d+ D. j' W& Z. ?5 s" z! |3 ~
0040469B |. 8941 04 MOV DWORD PTR DS:[ECX+4],EAX 存入0 H+ {6 [$ _: t- n' A4 u- N. a- ~) P
0040469E |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]
1 v2 y6 z' f$ a7 P( @2 w. W004046A1 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]4 `& x2 B$ Q2 f2 q6 \
004046A4 |. 8B42 10 MOV EAX,DWORD PTR DS:[EDX+10]
- M1 L2 X0 [2 V; H( n* H/ l004046A7 |. 8941 0C MOV DWORD PTR DS:[ECX+C],EAX 存入1B5 g/ z0 a& U' W
004046AA |. 8BE5 MOV ESP,EBP
' K% n& x) }5 `- W( K; u004046AC |. 5D POP EBP
2 t/ x9 e" z8 d$ f3 }. M! l9 E004046AD \. C2 0800 RETN 80 p" `7 X& Z% o8 u$ D- S1 p
6 I% z" R" A9 b, P/ S3 c, o
4 N2 r4 w( t; P1 ?* s
( X, L9 e7 S, W0 F, t: \; i! V( a, C9 A2 f' g
3 d6 ~$ x( z% q; x* g2 o/ b知道这些后 就可以改造了$ k9 n* S5 T" B. `, d8 K( z! t
先改字库
# p+ p, W, m+ u: S
* z7 { S! c1 \1 t% F8 m3 y: g" i4 A: O; A' @, w+ X
然后改成支持汉字的
; F! w' |/ D: C把4091d2 的 CMP EDX,0A 改成jmp* B* D$ f' u% y" s- h" y: C
跳到我的代码上去
( {- y5 e, g! e; {8 x0 [
5 w: _5 k% A6 ?; F; aAND EDX,0FF 去除高位的FF* x$ x0 p. C0 E, C0 ]
CMP EDX,0B0 比较是否汉字 跟比较80一样 因为我的字库是从 啊(B0 A1) 开始的
: N/ w# q, B" h9 Y( WJL Unpacked.004091F8 小于 B0的就跳回去
) X! q* i; Q( q4 k+ u& sMOV EDX,DWORD PTR SS:[EBP+8]
) S) R4 t% K. C( E" ]1 ?+ y7 b7 ?MOVSX EAX,WORD PTR DS:[EDX] 取2个字节 (支持汉字)5 Z% Y4 m/ N# i2 {% A
AND EAX,0FFFF 去除汉字高位的FF ^* w; C, f/ X2 M
MOV DWORD PTR SS:[EBP-40],EAX 存入形参
" b+ G5 B9 b3 u' p. I) ^/ H XLEA ECX,DWORD PTR SS:[EBP-28]
$ T9 X3 P6 m: d! F9 FPUSH ECX ; /Arg22 q5 Y- z: A# D$ y
MOV EDX,DWORD PTR SS:[EBP-40] ; |
I$ S0 {+ F' MPUSH EDX ; |Arg19 W, [& G1 z o# X
MOV ECX,DWORD PTR SS:[EBP-8] ; |
1 R# H+ |+ r- q L1 zCALL Unpacked.007CFF3C 这里是读取并存入 字符串X Y坐标
: V+ r: E- X% ^8 fMOV EAX,DWORD PTR SS:[EBP+8]2 a8 [* U: N5 j4 |6 l
ADD EAX,2 call出来后加2个字节
4 {1 q9 [. R0 r) eJMP Unpacked.004092177 X$ C% _5 s* o) L$ B% O9 ?& }
& B- Q+ @$ R/ ~3 O5 ~+ [6 |& j6 t3 q
% @3 J, A9 {! C- j. k& a
8 F4 i, j' D0 {" f7 g* F: `PUSH EBP# C; c1 o7 P- `8 [- i8 h) h
MOV EBP,ESP0 T* h( h( o+ E% e) H V
SUB ESP,0C1 r+ j( X. M3 R3 P) g4 K
MOV DWORD PTR SS:[EBP-C],ECX3 ^" A7 N' u7 K' t
MOV EAX,DWORD PTR SS:[EBP-C]
) H5 z7 z, @* Q! N( T! C$ BMOV ECX,DWORD PTR DS:[EAX+14]; k; h# y6 ]6 O
MOV DWORD PTR SS:[EBP-4],ECX0 X( I% X- n, [* i
CMP DWORD PTR SS:[EBP+8],0F9D7 边界检查 我这里最后个文字是 座(D7 F9)
% c& n* B; {8 y6 F* X: Z5 @JG SHORT Unpacked.007CFF8E 超出就绘制一个空白图片6 S& h3 n3 Y! U+ R3 ?) T: p
MOV ECX,DWORD PTR SS:[EBP+8] 从形参读取汉字 把汉字 放入ecx (我这里代码写的乱)
( I# ?& K, ], y; eXOR EAX,EAX
) n# L1 O) P7 ^! M; d1 m. w& SMOV AL,CL 把汉字第一个字节 放入eax
% ^8 C0 O1 S3 m0 H) m3 |4 wSHR CX,8 右移8位取第二个字节0 p, u! T4 w# p1 \8 v" Y& A6 C
XOR EDX,EDX4 @' [8 m4 ~0 e* a. C5 N
MOV DL,CL 把第2个字节放到edx去/ S. P( W) E" f, s$ d$ n. S! B4 V
SUB AL,0B0 这里是我自己写的算法 不用再读取码表了2 |* C$ a9 Q; F; a; ^2 I
SUB DL,0A1
- V8 _5 j3 e7 Y1 q& fIMUL EAX,EAX,10 我用的 宋体16 一个汉字是16X16
l, o# U5 ]8 qIMUL EDX,EDX,10
2 ?2 F( p( G! d/ M3 [- ZADD EAX,20 加上我图片原来的高度
6 h1 I6 q# ~# A- M9 f- @/ b6 j! [MOV ECX,DWORD PTR SS:[EBP+C]
2 X r# ^! E# tMOV DWORD PTR DS:[ECX],EDX2 Q" [0 `$ ^( d6 q& C6 Z
MOV DWORD PTR DS:[ECX+4],EAX7 Q3 v: t; u3 ]/ R
ADD EAX,104 \0 q3 g. ~" W9 [# V F1 u8 R& X
ADD EDX,10* }! X: p) B: w9 L4 g
MOV DWORD PTR DS:[ECX+8],EDX
7 @) h& P# E# iMOV DWORD PTR DS:[ECX+C],EAX9 e3 y+ f. }! ~$ w+ m4 [6 ^. ~# H
MOV ESP,EBP3 @- K- Q) K: d* @: D, |" @
POP EBP0 Z4 h: \7 Q( {" o. y& K3 x' A; \
RETN 8
1 g( `; }+ m3 I+ q1 z- ^. z0 O. S& Y
" P- M) |7 X' H! }0 o
|