上次在这翻资料的时候正好看到某人写的虚拟村庄3的汉化教程 手头上正好也有这游戏 所以决定小试下汉化 , S- T8 l& }0 E' W2 f
2 R" w( a0 q/ ^0 w: ~
在汉化前我们需要分析下游戏是如何显示字符串的 是贴图还是点阵
X2 z* `, [4 l7 ?2 D' B4 b这里是用bitblt贴上去的
6 f7 k" k5 ~% k/ u v知道是贴图就要寻找相应的字库和字符串 : ?5 L; r% D) F1 v& t
字库在image文件夹就能找到
( V9 s+ P2 |- W9 c, p, p% c字符串被压在了EXE里(脱壳后exe增大了3MB) 0 S- H# G4 ^! J! N4 h8 H' }0 t0 y
' @9 M! f) x9 K9 h1 B下面就是分析游戏是如何显示字符串的 - u1 ^8 O! Q6 m3 F7 y3 ~! k1 V1 S
用OD载入脱壳后的EXE文件 找到某个字符串下硬件访问 我这里断的是Quit) i& E5 Q1 W+ T9 b% S
8 d- D' C1 H8 F) f7 V& l+ K# m
按F9启动游戏& ^* N% T, l/ Y! G" {+ j
然后断在4F24D2处" F t# O0 ?9 h1 Z# T, R. h$ e
这里是读取字符串用的. R! X O6 H$ T: d
# J3 Q) p9 p0 r) S
分析下" n! W( a( F3 D/ X4 t& U2 \
004F24D0 |> 8B01 /MOV EAX,DWORD PTR DS:[ECX] 这里是读取4字节 quit" F2 n' F2 w# B
004F24D2 |. |BA FFFEFE7E |MOV EDX,7EFEFEFF 这里一块主要分析字符串是否已经到\03 `6 [( S+ M% s C
004F24D7 |. |03D0 |ADD EDX,EAX* W4 N+ A) o4 }+ p
004F24D9 |. |83F0 FF |XOR EAX,FFFFFFFF+ a* u' h" L' m' q6 P" O8 K
004F24DC |. |33C2 |XOR EAX,EDX9 ^5 h L) D% I% H
004F24DE |. |83C1 04 |ADD ECX,4 读取后面4个字节! L* P8 L @# U# H8 Z! {
004F24E1 |. |A9 00010181 |TEST EAX,81010100 1 R. u- e' V! G( r3 v+ _
004F24E6 |.^ 74 E8 |JE SHORT Unpacked.004F24D0 如果是4个00(也就是81010100)就跳出9 H/ m& W0 P5 z: E6 R
4 T# x) b: w/ {3 E# a这里要注意一下9 [4 k$ U: K* ]/ ]3 @
因为是4字节一取 \0处一定要是00 00 00 00
+ x( U7 ~- r6 N4 |3 C7 z如果要把Quit
' H- T0 \4 A9 d" O51 75 69 74 00 00 00 00 Quit....Quit....
; k9 V- [0 ?) U& x, R# W翻译成"退出吧" 就需要在加4字节
+ D' R, @- i2 h" y w' p+ U9 y/ h地方不够用咋办 幸好ecx是个指针 MOV EAX,DWORD PTR DS:[ECX]
' L" D5 ~# B2 @& X只要把ecx里的地址改成你的就OK了) m ]1 l+ X6 Q' G
, B+ A9 r! u6 n l继续找处理图片的地方
3 ~+ ?9 C4 Y! d+ c4 N; O# S; T一路跟下来到了/ p! p( o. b0 h6 Z8 y e
( r8 t: ]9 s, B j004F398C |. 83E6 F0 AND ESI,FFFFFFF0
6 p m+ l- b: @9 H- p* u004F398F |> 56 PUSH ESI ; /HeapSize = 5& g: `* a7 @3 l5 }2 C
004F3990 |. 6A 00 PUSH 0 ; |Flags = 0
" t3 y [9 r2 P004F3992 |. FF35 3C7B7B00 PUSH DWORD PTR DS:[7B7B3C] ; |hHeap = 00D60000
! l, p% M7 h! q) y7 k9 j004F3998 |. FF15 14815100 CALL DWORD PTR DS:[<&kernel32.HeapAlloc>>; \HeapAlloc
: d/ l. w) `! W- W2 q: Z* C& k004F399E |> 5E POP ESI9 ^9 j# q! m; W: r2 R
7 C q3 S) S6 Q8 h5 C
发现HeapAlloc 这个是用来分配内存的$ U5 a/ \0 j1 _' h. e; K e
F8步过 取eax的地址 就是将写入新的quit的地方
6 O; c8 o) p" }0 e' U对其下硬件访问 F9运行
# D+ K% x8 R$ }3 y! V" A断在了403811
8 z" ]6 x6 {5 h/ Y在F9几次 断在了4091c4
6 R' m s+ h4 l4 z/ J8 ]) B7 u在F9几次 回到了403811( d( @* s/ H4 ^# g: N- X
) b' s& F% ?- {0 ^6 h
确定就是这2处地方了
1 T8 T; l6 `. s0 t( k4 \这里我选择了4091c4 因为在跟踪403811后发现这里的数据没用 B9 }1 F6 l- w% }) \% e
h! Q' ~ ?4 O
004091BE |> 8B55 08 /MOV EDX,DWORD PTR SS:[EBP+8]
' M& C" n* W! l/ j' R004091C1 |. |0FBE02 |MOVSX EAX,BYTE PTR DS:[EDX] 取第一个字节Q( W3 r; ^1 N3 }) j) Z
004091C4 |. |85C0 |TEST EAX,EAX
+ L# a I4 T5 T6 {; v4 B8 ?4 t: r& y004091C6 |. |0F84 E2000000 |JE Unpacked.004092AE 字符串到达\0就跳出
% Q* X/ l+ `9 k& }+ Q! ?004091CC |. |8B4D 08 |MOV ECX,DWORD PTR SS:[EBP+8]
$ |. Z8 _) |2 j+ L5 q) ^1 s004091CF |. |0FBE11 |MOVSX EDX,BYTE PTR DS:[ECX] 取第一个字节Q- C2 Y+ N# S7 V) B9 E
004091D2 |. |83FA 0A |CMP EDX,0A 判断是否是空格
$ Q' I! q0 V3 M5 E) m" u004091D5 |. |75 21 |JNZ SHORT Unpacked.004091F8( h+ Y$ m. i7 J/ F a
004091D7 |. |8B45 E8 |MOV EAX,DWORD PTR SS:[EBP-18]" Y3 V& v8 A9 [, _
004091DA |. |8945 0C |MOV DWORD PTR SS:[EBP+C],EAX
! s p+ N6 B N' ^ o- E& |004091DD |. |6A 00 |PUSH 0 ; /Arg1 = 00000000- Y' l# j; c/ Y: G
004091DF |. |8B4D F8 |MOV ECX,DWORD PTR SS:[EBP-8] ; |- y' s2 L0 P, O9 F
004091E2 |. |E8 C9A7FFFF |CALL Unpacked.004039B0 ; \Unpacked.004039B0
$ D6 B# }; }# G7 @ M004091E7 |. |0345 10 |ADD EAX,DWORD PTR SS:[EBP+10]; N1 c3 a) G/ }0 g
004091EA |. |8945 10 |MOV DWORD PTR SS:[EBP+10],EAX0 D! Z* d5 H; E5 g% D3 `# o
004091ED |. |8B4D 08 |MOV ECX,DWORD PTR SS:[EBP+8]
" t' N. O4 P$ P4 N' }6 V1 r+ x004091F0 |. |83C1 01 |ADD ECX,1
& P& o: m1 F4 m9 E004091F3 |. |894D 08 |MOV DWORD PTR SS:[EBP+8],ECX
: r. I4 m& I; k, z. Z004091F6 |.^ EB C6 |JMP SHORT Unpacked.004091BE: ]* {- [1 q) o% ]
004091F8 |> |8B55 08 |MOV EDX,DWORD PTR SS:[EBP+8] 不是的空格跳到这里- B" e1 v2 r% E# Q+ V2 `) I
004091FB |. |0FBE02 |MOVSX EAX,BYTE PTR DS:[EDX] 把Q给EAX (实现双字节 就要让他取WORD 这里需要改造)
/ \# n7 U s t3 N t' k4 A004091FE |. |8945 C0 |MOV DWORD PTR SS:[EBP-40],EAX 把Q 放到参数中去
8 \) V: N; O: @ ~# k00409201 |. |8D4D D8 |LEA ECX,DWORD PTR SS:[EBP-28]% v" u+ q" t) o& ^/ V9 d# J
00409204 |. |51 |PUSH ECX ; /Arg2
; H; T, a$ I, T9 A+ W5 Q00409205 |. |8B55 C0 |MOV EDX,DWORD PTR SS:[EBP-40] ; |) r/ Z/ A( `3 V1 ]
00409208 |. |52 |PUSH EDX ; |Arg1 压入Q
+ \- c6 m5 ^; f( ?6 b) m00409209 |. |8B4D F8 |MOV ECX,DWORD PTR SS:[EBP-8] ; |
8 H7 [& X* z/ a5 T* U8 A0040920C |. |E8 0FB4FFFF |CALL Unpacked.00404620 ; \Unpacked.00404620 这里是关键
& f2 h6 D* R% W6 X2 L' U7 B. ?00409211 |. |8B45 08 |MOV EAX,DWORD PTR SS:[EBP+8]8 c/ N. W* V" [* R. p7 w$ ~
00409214 |. |83C0 01 |ADD EAX,1 读完Q后读u) M: W$ M- Z5 @% H2 m% v4 g3 X7 |7 x
00409217 |. |8945 08 |MOV DWORD PTR SS:[EBP+8],EAX
$ H5 Z+ E0 H* Q5 V- k1 X/ g% g5 `0040921A |. |8D4D D8 |LEA ECX,DWORD PTR SS:[EBP-28]
2 e3 Q; |4 T9 g- ` {$ P0040921D |. |E8 5E8BFFFF |CALL Unpacked.00401D80 这里存入了画Q需要的长度2 f$ m* e& I+ Z4 B* i6 l
00409222 |. |8945 D4 |MOV DWORD PTR SS:[EBP-2C],EAX# K4 f* ?6 t2 f0 c4 y; w8 E
00409225 |. |837D D4 00 |CMP DWORD PTR SS:[EBP-2C],0
& g% E. W0 {! n0 ?6 u00409229 |. |74 7E |JE SHORT Unpacked.004092A9
, A6 S+ v% ^4 X. y! j7 \' V& V
$ W( q$ F7 ^) ?: F" J* J
5 ~% ?, o# ?/ ?: |5 L2 O3 {6 [$ N0 \1 \6 [& b4 a9 F# J8 `/ A; v) d7 E
+ ?$ z) [$ s+ H/ g7 l# h' R5 @" R+ u
) H" U8 n5 c6 h4 u0 o, \: J% H
00404620 /$ 55 PUSH EBP c4 o" z5 o/ ^5 Q# c) Y4 J. q( m
00404621 |. 8BEC MOV EBP,ESP$ N( w& U" g4 Y x* g2 j8 |
00404623 |. 83EC 0C SUB ESP,0C
/ `% g% k! C. T6 o( K, f00404626 |. 894D F4 MOV DWORD PTR SS:[EBP-C],ECX 4 s% T8 a/ Z) _7 j
00404629 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]" ]3 e# u4 M% i+ G2 J8 I
0040462C |. 8B48 14 MOV ECX,DWORD PTR DS:[EAX+14]2 a( B7 g& `; [6 H' f3 a/ j+ \$ ^
0040462F |. 894D FC MOV DWORD PTR SS:[EBP-4],ECX
) L2 b5 p$ ]( u3 T! ~! X2 N00404632 |. 837D 08 00 CMP DWORD PTR SS:[EBP+8],0 这里就是边界检查
3 ]( l t! `+ F* q z% u00404636 |. 7D 0D JGE SHORT Unpacked.00404645
* P# d1 f: F- D/ K2 e* U* K00404638 |. 8A55 08 MOV DL,BYTE PTR SS:[EBP+8]; B5 ?3 M* V/ k; c0 v+ e5 `
0040463B |. 8855 FB MOV BYTE PTR SS:[EBP-5],DL; ]9 R1 _' a2 i$ Z( I" E- T
0040463E |. 0FB645 FB MOVZX EAX,BYTE PTR SS:[EBP-5]
) m/ l3 U2 U; w9 D00404642 |. 8945 08 MOV DWORD PTR SS:[EBP+8],EAX, P' G5 | L) R6 H# }6 R% ~2 X
00404645 |> 817D 08 00010>CMP DWORD PTR SS:[EBP+8],100 边界检查; l( f3 s* X" Z; e) i5 S9 l
0040464C |. 7D 18 JGE SHORT Unpacked.00404666
* J+ d4 \, a6 m) n5 A1 m* X* W- ?* h0040464E |. 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+8]2 g+ y3 S1 K, P8 G
00404651 |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]2 |* n# l* T. ^& l# L* Z. c
00404654 |. 8B448A 18 MOV EAX,DWORD PTR DS:[EDX+ECX*4+18]0 u# X: Q4 k( o
00404658 |. 6BC0 14 IMUL EAX,EAX,144 y. e& x3 l- ]- [) J% \
0040465B |. 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-C]
* Q H: V# a7 z, i' A$ b# a0040465E |. 0341 14 ADD EAX,DWORD PTR DS:[ECX+14]' @/ m! n3 g Q- @: e/ ?
00404661 |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX6 ~( y0 Q" J4 P3 r5 M6 R, _
00404664 |. EB 15 JMP SHORT Unpacked.0040467B/ ?- u& J6 c$ }9 U! ~
00404666 |> 8B55 08 MOV EDX,DWORD PTR SS:[EBP+8] 这里一块是算Q的码表, G0 K7 H! i8 j2 W
- H+ L; Y% D. u" u% B
- N3 d4 E# L1 F, M$ V( G. u2 [/ C) x+ p$ g
0054AA48 51 00 00 00 2D 02 00 00 00 00 00 00 3C 02 00 00 Q...-......<.. W/ I$ M. j: a8 [ f
0054AA58 1B 00 00 00 ...5 o# R" D3 F& M2 L, L7 ~. z2 S0 i. l w
: V+ Z! O; v( _51就是字符Q
) k! d5 z- H1 O2D 02 00 00% g( l) } i2 S. g! v/ I6 b
00 00 00 00# u6 n4 Z& l- h q4 Z: R9 d
3C 02 00 00
6 M% `5 D9 N2 F2 K( ^/ _1B 00 00 00
+ M* g$ _2 X3 m" A+ w8 ?/ w' {& Y9 S- F; T0 }/ ?$ P5 y
A━━┓
^& @- u- U- H ┃ Q ┃
M; k6 y2 C6 @5 S: P. \' o( u. [ ┗━━B
# W; z: v: B0 Z4 F& u) H) M# `5 @- I0 X/ L$ q) c% w0 X# z
A的坐标 (22D,0)& C7 }- j6 @! a4 c4 r1 U, G
B的坐标 (23C,1B)( Y; @# V! c% p6 }1 V* p" Z
: Q. w) U( s9 a; `$ k
5 s' k( w' u: k. I. f) q$ j4 E1 @- F7 }7 u5 H b) z" s
00404669 |. 81E2 FF7F0000 AND EDX,7FFF
! w# `) W$ S: {' I0040466F |. 6BD2 14 IMUL EDX,EDX,14
7 Z' d. { H. S+ m, n4 ]; g00404672 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]6 T0 O, c1 [. x$ [
00404675 |. 0350 14 ADD EDX,DWORD PTR DS:[EAX+14]
* [+ ]5 j; N5 X: N00404678 |. 8955 FC MOV DWORD PTR SS:[EBP-4],EDX& Q) c! j! Q7 H6 d
0040467B |> 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]8 Y" z: v9 G% z" _0 V% E" A. n
0040467E |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
' ~! z2 |) K2 }( Q% `& Y00404681 |. 8B42 04 MOV EAX,DWORD PTR DS:[EDX+4]
2 \9 d- @: g7 k8 ^/ B1 q5 U00404684 |. 8901 MOV DWORD PTR DS:[ECX],EAX 存入22D
" D# Q$ Q6 F; T5 r00404686 |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]& I) u3 f S& X+ K
00404689 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
2 F/ _6 J: Z, p8 k3 _5 C! q0040468C |. 8B42 0C MOV EAX,DWORD PTR DS:[EDX+C]/ g# T2 }$ k/ W. p$ _5 ^ B
0040468F |. 8941 08 MOV DWORD PTR DS:[ECX+8],EAX 存入23C3 }0 G+ Y. H3 O
00404692 |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]1 r& _3 e i' G1 m
00404695 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
6 N% ^. h, W& C; W00404698 |. 8B42 08 MOV EAX,DWORD PTR DS:[EDX+8]
9 W, e+ O& R# X2 j3 \4 w* {0040469B |. 8941 04 MOV DWORD PTR DS:[ECX+4],EAX 存入0
/ |# |, E Y4 X; ~" X, @0 N0040469E |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]
. y6 F! @7 Y3 g, q" n& z004046A1 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
4 g+ U# Y" C" l+ B6 Y% j5 w004046A4 |. 8B42 10 MOV EAX,DWORD PTR DS:[EDX+10]
5 F; w ^. N+ g9 }4 k: r" D1 P004046A7 |. 8941 0C MOV DWORD PTR DS:[ECX+C],EAX 存入1B
/ L4 d# q) @. P( `. F! {9 ^. r004046AA |. 8BE5 MOV ESP,EBP( k% [! H( T3 j. U, I& f
004046AC |. 5D POP EBP
( V) l7 f6 ]% x0 A/ i5 @004046AD \. C2 0800 RETN 8/ ] ]" N d8 L4 D& y* U
, ]; Q& a' Q& N' |2 V! h5 j
5 _% U0 p5 K' ^$ X& R! L4 J3 v
- m; `2 x# K2 T* p" e! t7 i
3 K3 s" H5 a8 b$ Y( Z+ I
& j# ], a5 e5 `2 E知道这些后 就可以改造了
+ n. E7 {8 h ^! v先改字库. q+ K4 w. A5 w7 \# w) g M5 p
# O( H! S) t. m) M3 O$ v
0 D$ O& k$ E! E1 l3 Q% x7 g/ H6 D- E1 {然后改成支持汉字的
5 ?7 ]6 e" a# R f* O1 R1 [# ]( L把4091d2 的 CMP EDX,0A 改成jmp& Q0 n( u6 h% Q, c- X
跳到我的代码上去8 ^/ C+ r( N0 x. i5 d# x
0 y$ l- B |# eAND EDX,0FF 去除高位的FF
' _' P4 q# Z7 ]9 M& G* t2 }2 SCMP EDX,0B0 比较是否汉字 跟比较80一样 因为我的字库是从 啊(B0 A1) 开始的/ z& @6 a }5 t4 h2 u$ ?
JL Unpacked.004091F8 小于 B0的就跳回去4 g: h* Z) o( w+ q' Q; h. r
MOV EDX,DWORD PTR SS:[EBP+8]7 H; U1 B$ U' r: R
MOVSX EAX,WORD PTR DS:[EDX] 取2个字节 (支持汉字)$ H$ ^* C& n6 P, w
AND EAX,0FFFF 去除汉字高位的FF6 ]& B: S# ]9 g' g
MOV DWORD PTR SS:[EBP-40],EAX 存入形参% H' ~! D# R( o0 p. E
LEA ECX,DWORD PTR SS:[EBP-28]8 }/ A- }, {, f# W/ K
PUSH ECX ; /Arg2) L' w7 ` S N
MOV EDX,DWORD PTR SS:[EBP-40] ; |
. z' i# N1 c2 A4 c: Z5 u% N2 xPUSH EDX ; |Arg14 [6 t" I5 T1 n4 o# b1 p
MOV ECX,DWORD PTR SS:[EBP-8] ; |% O% m4 Z+ x. g9 p
CALL Unpacked.007CFF3C 这里是读取并存入 字符串X Y坐标
8 ?2 l7 X3 J3 {' [MOV EAX,DWORD PTR SS:[EBP+8]7 \3 [. J- O: J' e2 h! k- v
ADD EAX,2 call出来后加2个字节
% ~" B3 O; E" P& ^JMP Unpacked.00409217
; O3 L, S0 X: n9 [. H; [: G) W, E/ |
; X4 V; x" B2 B8 v( A
3 x |( x0 t5 {9 y+ X. U
K0 ~8 s& R" M: ]5 p/ ~& qPUSH EBP
/ a0 k$ v1 r5 pMOV EBP,ESP
# v! q" y/ w5 ]) o- B- oSUB ESP,0C
+ X7 V% D7 y3 a; F5 EMOV DWORD PTR SS:[EBP-C],ECX
: U5 ]' R# @5 @4 T. oMOV EAX,DWORD PTR SS:[EBP-C]
) [3 N) V6 f. ^* m5 eMOV ECX,DWORD PTR DS:[EAX+14]
% [* G" j9 G0 k ?" Y- t/ VMOV DWORD PTR SS:[EBP-4],ECX Y; Z# l) o% g! P1 ?4 b$ Y
CMP DWORD PTR SS:[EBP+8],0F9D7 边界检查 我这里最后个文字是 座(D7 F9)
0 k: W+ ~/ Z4 J" ~, wJG SHORT Unpacked.007CFF8E 超出就绘制一个空白图片
0 j. i: v3 v* d: ^8 z h' p, G8 IMOV ECX,DWORD PTR SS:[EBP+8] 从形参读取汉字 把汉字 放入ecx (我这里代码写的乱)# S. F; v- _* G0 X
XOR EAX,EAX Q& p2 e0 v( U, i# e# {
MOV AL,CL 把汉字第一个字节 放入eax5 e+ W @! u# \$ P9 L& I
SHR CX,8 右移8位取第二个字节
% f# R: N7 ^ L( {XOR EDX,EDX
: K" F& `7 Q3 r) }3 c" qMOV DL,CL 把第2个字节放到edx去& N& p$ i1 T9 J5 K
SUB AL,0B0 这里是我自己写的算法 不用再读取码表了/ V, i+ {0 \2 E: G$ p
SUB DL,0A15 c' y: p$ U* n0 z- P2 y6 _
IMUL EAX,EAX,10 我用的 宋体16 一个汉字是16X16$ D4 X+ Y0 x' Z! p& ~
IMUL EDX,EDX,10
: h, e1 v! C! n5 @& }ADD EAX,20 加上我图片原来的高度
, d0 d* H0 U- jMOV ECX,DWORD PTR SS:[EBP+C]
3 {' y0 o; }9 T4 \% |MOV DWORD PTR DS:[ECX],EDX% }" z1 ^* N2 h" j* n1 L
MOV DWORD PTR DS:[ECX+4],EAX- X3 p. I$ O6 v4 m9 J, m
ADD EAX,10
8 M6 r# X8 [& S5 q0 QADD EDX,10
3 |& L* P9 w* j" QMOV DWORD PTR DS:[ECX+8],EDX3 i( ?! n# A4 K9 d1 X' g* W
MOV DWORD PTR DS:[ECX+C],EAX* i2 }/ i0 C* K4 }0 s
MOV ESP,EBP
% a4 F" F0 j4 ?7 t, `) Q4 m! `; n# BPOP EBP
) h* W- v- V7 E& `8 mRETN 85 f: ?( A7 \( g( ^/ Y8 K8 g& v
, T0 P: t2 d6 B5 y. J
/ F7 D* S7 @1 F+ O |