上次在这翻资料的时候正好看到某人写的虚拟村庄3的汉化教程 手头上正好也有这游戏 所以决定小试下汉化 4 h/ k& X' B) C& T3 J
" X E5 w$ i: Y
在汉化前我们需要分析下游戏是如何显示字符串的 是贴图还是点阵 , x! G; ~) R2 Y2 [2 ]. t2 Y
这里是用bitblt贴上去的 % X1 C' W* m" t9 J1 z; Z
知道是贴图就要寻找相应的字库和字符串
0 \1 @. ?, l' S4 |6 _2 P+ m+ h字库在image文件夹就能找到
& N9 K- o" z6 }2 H) @字符串被压在了EXE里(脱壳后exe增大了3MB)
, d1 B+ f2 z3 g( d- J5 h* c0 e" ^3 H) J0 S. `
下面就是分析游戏是如何显示字符串的
# O% ^+ Y+ K, B- m$ P7 X用OD载入脱壳后的EXE文件 找到某个字符串下硬件访问 我这里断的是Quit
8 i! D& e) U5 z0 P$ I
7 j5 r# t. |$ [% n按F9启动游戏7 `* S# M$ V( ?1 a3 x- ?8 E/ k
然后断在4F24D2处
+ T7 @4 Y2 M1 s6 V8 z这里是读取字符串用的
( E- s, Z e" ] ! i& k5 `1 Q! n' {
分析下9 {# {! v( L4 f# M" U$ k0 @" x
004F24D0 |> 8B01 /MOV EAX,DWORD PTR DS:[ECX] 这里是读取4字节 quit
) @; c6 O8 c# X3 @+ R004F24D2 |. |BA FFFEFE7E |MOV EDX,7EFEFEFF 这里一块主要分析字符串是否已经到\0* W7 p4 X" H# I* Z3 d. A' c M
004F24D7 |. |03D0 |ADD EDX,EAX
7 n3 e# z% a$ w V8 T. @004F24D9 |. |83F0 FF |XOR EAX,FFFFFFFF( x* J) r( D0 X3 b& Z$ l8 F% r
004F24DC |. |33C2 |XOR EAX,EDX7 q0 [1 Y3 T- p5 v) W! h a
004F24DE |. |83C1 04 |ADD ECX,4 读取后面4个字节
$ j: F# g3 l3 q6 s004F24E1 |. |A9 00010181 |TEST EAX,81010100 ; z; n$ o* l. j( P# t; n* x4 O) C
004F24E6 |.^ 74 E8 |JE SHORT Unpacked.004F24D0 如果是4个00(也就是81010100)就跳出
# \2 l# k. c3 r5 G0 P: F) a% i" L% k& Y5 V9 F1 v' C! \) F! O9 U# I
这里要注意一下
0 B! D$ W& Y. h G6 y3 s, u因为是4字节一取 \0处一定要是00 00 00 00
2 N7 D" p* S2 _2 J% w1 v如果要把Quit
7 E- m4 g e& f6 ]5 Q3 n3 f9 Y" ]; x* w51 75 69 74 00 00 00 00 Quit....Quit....
; z6 Y0 m% [" V4 H0 \4 I) j8 [翻译成"退出吧" 就需要在加4字节& J( u2 @3 k) d
地方不够用咋办 幸好ecx是个指针 MOV EAX,DWORD PTR DS:[ECX]; u0 Y* d, S& x6 q
只要把ecx里的地址改成你的就OK了2 j/ w' v6 l1 I/ g
9 S0 x5 `( N% w( u
继续找处理图片的地方2 W! V- o% x* I. B8 N9 Q
一路跟下来到了6 B4 O: Q; q7 {
4 ^+ _5 I, ~; V6 F1 g. A& B0 Y* o% c# q004F398C |. 83E6 F0 AND ESI,FFFFFFF0
& S0 d. n7 Z W+ u* ~7 e5 c004F398F |> 56 PUSH ESI ; /HeapSize = 5
+ r$ C. G8 e! {1 `- g4 E004F3990 |. 6A 00 PUSH 0 ; |Flags = 0
9 i- J2 r, q7 ]0 S* P/ Y6 j* f6 y# H004F3992 |. FF35 3C7B7B00 PUSH DWORD PTR DS:[7B7B3C] ; |hHeap = 00D60000
* s6 O$ H* m, Y" d. J004F3998 |. FF15 14815100 CALL DWORD PTR DS:[<&kernel32.HeapAlloc>>; \HeapAlloc
6 V' ^: R5 n3 H% C& g& ?3 ]) _004F399E |> 5E POP ESI
. S2 i: M" Z! q8 n4 m, L5 J+ [5 z( m" o
发现HeapAlloc 这个是用来分配内存的
1 a& W1 ?- W; L6 ?3 aF8步过 取eax的地址 就是将写入新的quit的地方4 M1 _6 j6 G( @5 R9 h( T" d
对其下硬件访问 F9运行
9 m: r7 ^; {( i4 I: x; `断在了403811
! I3 L2 a4 q/ J; ]在F9几次 断在了4091c4
& g2 P8 ?; l" e3 S在F9几次 回到了403811
' c$ B# R( a9 m# |8 O! V7 ?0 C
! @' j, ~0 E+ r, D7 R) Q" k" h+ Q确定就是这2处地方了6 E+ L% N: H& r! u$ ~8 S1 x
这里我选择了4091c4 因为在跟踪403811后发现这里的数据没用$ e& }/ Z. B& V m3 v5 O
) A$ Z( o @, |* \! D
004091BE |> 8B55 08 /MOV EDX,DWORD PTR SS:[EBP+8]& c! b) y" ?. E" I& h5 I- J
004091C1 |. |0FBE02 |MOVSX EAX,BYTE PTR DS:[EDX] 取第一个字节Q
( z4 v7 \* a9 C3 z& w$ n7 A5 u004091C4 |. |85C0 |TEST EAX,EAX " I8 C2 n8 `' }% B/ y C8 x$ E9 y n
004091C6 |. |0F84 E2000000 |JE Unpacked.004092AE 字符串到达\0就跳出
6 n. N# @" h( o3 I1 k, b004091CC |. |8B4D 08 |MOV ECX,DWORD PTR SS:[EBP+8]6 Q6 f& M* \/ R3 ~+ n
004091CF |. |0FBE11 |MOVSX EDX,BYTE PTR DS:[ECX] 取第一个字节Q
8 q9 P' f; Q, c' c% h5 c004091D2 |. |83FA 0A |CMP EDX,0A 判断是否是空格9 y6 I6 t( a* t; S5 W
004091D5 |. |75 21 |JNZ SHORT Unpacked.004091F8
: _. G# t% C2 y) y/ L004091D7 |. |8B45 E8 |MOV EAX,DWORD PTR SS:[EBP-18]
8 H; }2 s, p- g7 ?8 r) [, N, U004091DA |. |8945 0C |MOV DWORD PTR SS:[EBP+C],EAX5 v4 ]- a9 n: s1 e* ~
004091DD |. |6A 00 |PUSH 0 ; /Arg1 = 00000000
/ I0 i$ v Z" L* W: d3 u004091DF |. |8B4D F8 |MOV ECX,DWORD PTR SS:[EBP-8] ; |
$ g/ J7 D& l" \) O* y3 I0 z/ P004091E2 |. |E8 C9A7FFFF |CALL Unpacked.004039B0 ; \Unpacked.004039B08 B: u0 W; V& T) R8 S! d
004091E7 |. |0345 10 |ADD EAX,DWORD PTR SS:[EBP+10]
6 v5 @% J$ v7 }: ^+ o' z3 R) _004091EA |. |8945 10 |MOV DWORD PTR SS:[EBP+10],EAX
/ h' `. @. W5 X004091ED |. |8B4D 08 |MOV ECX,DWORD PTR SS:[EBP+8]
/ z1 i" G N4 q7 f004091F0 |. |83C1 01 |ADD ECX,1; s: ~0 @) E; b# h
004091F3 |. |894D 08 |MOV DWORD PTR SS:[EBP+8],ECX
% {% ~/ o( A. X6 x1 C) w2 V& v% H004091F6 |.^ EB C6 |JMP SHORT Unpacked.004091BE
- O; p& V3 @+ Q1 b004091F8 |> |8B55 08 |MOV EDX,DWORD PTR SS:[EBP+8] 不是的空格跳到这里0 B% [2 Q4 V+ p6 P2 g, c9 |/ O( j
004091FB |. |0FBE02 |MOVSX EAX,BYTE PTR DS:[EDX] 把Q给EAX (实现双字节 就要让他取WORD 这里需要改造)) L$ p& L) O- I: H8 x& w2 B
004091FE |. |8945 C0 |MOV DWORD PTR SS:[EBP-40],EAX 把Q 放到参数中去
8 Y* C0 b \) s1 R- t& I1 s00409201 |. |8D4D D8 |LEA ECX,DWORD PTR SS:[EBP-28]# \0 L9 K B! \+ K5 N/ Q X
00409204 |. |51 |PUSH ECX ; /Arg2
$ d/ x! q, E( u00409205 |. |8B55 C0 |MOV EDX,DWORD PTR SS:[EBP-40] ; |
$ M1 X9 V' l1 R/ _+ c00409208 |. |52 |PUSH EDX ; |Arg1 压入Q
3 d/ e& a9 t8 L7 i! J00409209 |. |8B4D F8 |MOV ECX,DWORD PTR SS:[EBP-8] ; |
1 v! Z3 q1 ?5 f0040920C |. |E8 0FB4FFFF |CALL Unpacked.00404620 ; \Unpacked.00404620 这里是关键; H% c# ~$ z% h4 T% [
00409211 |. |8B45 08 |MOV EAX,DWORD PTR SS:[EBP+8]/ c- g% e( g) O
00409214 |. |83C0 01 |ADD EAX,1 读完Q后读u% p+ @. y7 {% M) Z1 N
00409217 |. |8945 08 |MOV DWORD PTR SS:[EBP+8],EAX8 V/ ]5 H! H9 x$ I
0040921A |. |8D4D D8 |LEA ECX,DWORD PTR SS:[EBP-28]
& I8 U9 N* a! f$ U3 m2 y' F0040921D |. |E8 5E8BFFFF |CALL Unpacked.00401D80 这里存入了画Q需要的长度9 `) `4 F A8 I3 _& d! h
00409222 |. |8945 D4 |MOV DWORD PTR SS:[EBP-2C],EAX5 e5 Q' }( O" L" b
00409225 |. |837D D4 00 |CMP DWORD PTR SS:[EBP-2C],0" U U) [% ^: C9 c
00409229 |. |74 7E |JE SHORT Unpacked.004092A9 H0 |- V- S+ j! q( u
8 ?- ]1 y) d8 B" c) _! }$ ]. h- ]
h5 A% K, V$ w1 x4 t. w
+ Q q1 }9 o2 G
4 o9 K, u+ x" \5 o e: @7 m) G1 M
- H$ R$ q' j' S; B: o# y" S G& f; d6 K% W8 d
00404620 /$ 55 PUSH EBP' @* ]0 N4 P+ B! p" ^* @+ X8 z: r
00404621 |. 8BEC MOV EBP,ESP
0 Y4 @* J' Q; Q7 }8 Q00404623 |. 83EC 0C SUB ESP,0C, T% g9 M" M F! U
00404626 |. 894D F4 MOV DWORD PTR SS:[EBP-C],ECX
0 m/ x% s* K% [# m00404629 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
6 \& h q- m/ e0040462C |. 8B48 14 MOV ECX,DWORD PTR DS:[EAX+14]
! ?/ W& [& B& V* V" W' w0040462F |. 894D FC MOV DWORD PTR SS:[EBP-4],ECX
R5 {( S7 _! r( j. ~1 g7 D+ L00404632 |. 837D 08 00 CMP DWORD PTR SS:[EBP+8],0 这里就是边界检查1 `$ Z$ g, k* M6 g
00404636 |. 7D 0D JGE SHORT Unpacked.00404645
" w6 [: s; t# ~1 k, ~9 o4 m00404638 |. 8A55 08 MOV DL,BYTE PTR SS:[EBP+8]
9 E: F; w' M$ e0040463B |. 8855 FB MOV BYTE PTR SS:[EBP-5],DL* [) q$ q; J/ _" m# d- U$ B% O+ \
0040463E |. 0FB645 FB MOVZX EAX,BYTE PTR SS:[EBP-5]; v! h8 I% [! ]# I3 t
00404642 |. 8945 08 MOV DWORD PTR SS:[EBP+8],EAX
1 r, S: ~$ H% P2 }1 b$ ]9 d00404645 |> 817D 08 00010>CMP DWORD PTR SS:[EBP+8],100 边界检查& j8 t5 `) N* E
0040464C |. 7D 18 JGE SHORT Unpacked.00404666( s2 M" Z+ ]7 Q- v4 e& a( \
0040464E |. 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+8] E( w" f& W6 e0 z
00404651 |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]' t6 c$ C9 B+ K/ R2 X
00404654 |. 8B448A 18 MOV EAX,DWORD PTR DS:[EDX+ECX*4+18]* M A* q$ Q! ^! T& D& D* L/ \
00404658 |. 6BC0 14 IMUL EAX,EAX,148 n3 R% a( Z$ C
0040465B |. 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-C]
# W+ ^& T6 a, n6 ]$ R5 k0040465E |. 0341 14 ADD EAX,DWORD PTR DS:[ECX+14]) C. t2 p' o `9 p- M
00404661 |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX+ w6 \) S8 K( M+ A& y, h
00404664 |. EB 15 JMP SHORT Unpacked.0040467B
, c! G+ f6 F1 ?4 h$ h1 I' Z00404666 |> 8B55 08 MOV EDX,DWORD PTR SS:[EBP+8] 这里一块是算Q的码表. N* ~+ l) y) X; `
6 E- [1 b0 [3 L: g0 D# `& i& @2 a; q5 I3 [, `3 i
4 C0 F( P4 D& F9 N8 @0054AA48 51 00 00 00 2D 02 00 00 00 00 00 00 3C 02 00 00 Q...-......<..
, V/ C" S" E3 `; {% L& ?8 l0054AA58 1B 00 00 00 ...
0 n4 C" n6 M/ Z/ E9 o, [
4 f* ?+ W+ L5 ^: g51就是字符Q) z; n; B8 H4 e( b0 E( [
2D 02 00 00: l! {) i' l5 |8 C4 j M/ }
00 00 00 00
y+ u# i1 T I7 A2 w, v3C 02 00 00
) z" R6 P) g7 Z# y6 ?5 k1B 00 00 00
- Z; m. A( I5 x5 P7 s$ r" X3 e! \8 b {7 o5 F# G$ i
A━━┓ ! b0 `' [$ M2 a1 V4 P
┃ Q ┃
( y) U( |: r: A& n. v0 _, @ ┗━━B/ l- W V7 J, p9 s% A& N9 c
0 k! N" P+ g$ B
A的坐标 (22D,0)# G4 E$ x' T4 `# T7 M# ?5 Q* o
B的坐标 (23C,1B)# M; H5 _+ P) u" j j
# `- J" H/ L& Z: C7 p9 N
4 B- g% A2 w# s" O8 Y, i$ J$ P
$ I* E; i9 |8 r1 L00404669 |. 81E2 FF7F0000 AND EDX,7FFF
# r* @* L5 A7 k- V( M. c. x0040466F |. 6BD2 14 IMUL EDX,EDX,14
3 E6 N2 E( Y+ b2 G00404672 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]* G2 u9 P5 F: U1 a
00404675 |. 0350 14 ADD EDX,DWORD PTR DS:[EAX+14]$ R9 l1 @" i- n! |% j& w
00404678 |. 8955 FC MOV DWORD PTR SS:[EBP-4],EDX+ `0 H4 J3 o8 _( x+ n5 |! X
0040467B |> 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]" ?# b8 c3 U) |# R4 h# M
0040467E |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]0 G: ~# [, G% f& Z- Z2 N# r
00404681 |. 8B42 04 MOV EAX,DWORD PTR DS:[EDX+4]/ x& }, \- L2 S, E' h3 M; j
00404684 |. 8901 MOV DWORD PTR DS:[ECX],EAX 存入22D
I% t' g. { e2 M& z: O00404686 |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]
: Z7 X" D% L; _7 m' w2 B' J# ?00404689 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]/ ^" D# ?% Y) h; m- j. r9 v
0040468C |. 8B42 0C MOV EAX,DWORD PTR DS:[EDX+C]
6 O' r* [5 p+ Q# v; v9 t0040468F |. 8941 08 MOV DWORD PTR DS:[ECX+8],EAX 存入23C
5 r5 A8 q& |. y6 E$ b" G00404692 |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]
$ s1 C. \% e2 A) @& U/ K00404695 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
! G% H, H. j9 ~; O7 n00404698 |. 8B42 08 MOV EAX,DWORD PTR DS:[EDX+8]: ~6 u! x- K/ t2 w0 `& e: d$ h
0040469B |. 8941 04 MOV DWORD PTR DS:[ECX+4],EAX 存入00 }& `. y1 E T
0040469E |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]
2 r& a/ R! {* m5 i5 P6 Q( d8 \004046A1 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]; L6 _8 w8 V) j: P9 ~0 L/ b8 M: A; I
004046A4 |. 8B42 10 MOV EAX,DWORD PTR DS:[EDX+10]- q% q0 o" j, h2 q0 V, A9 q
004046A7 |. 8941 0C MOV DWORD PTR DS:[ECX+C],EAX 存入1B; |. a5 _% M! ~, n( U! R, ~) V
004046AA |. 8BE5 MOV ESP,EBP
C6 e) v5 P' M$ E3 T. w" w( O004046AC |. 5D POP EBP
+ J) O. t3 g" l' p6 ^004046AD \. C2 0800 RETN 8
; {8 B) U. V9 W: v6 j" M) G6 O7 l- {9 W2 P/ M4 A7 z
3 v$ d/ w7 _! H/ H$ M; l U, w- V& N4 j! O W! e+ A. o) `
! N% g5 x2 q& v1 I7 ]
- g5 _$ D* ~8 \! K0 P* r8 J8 d5 v% t知道这些后 就可以改造了
+ _5 B w! t3 B4 @1 N0 Z$ K先改字库
8 s5 l7 @1 ^1 `" i" y. K/ V . s U$ b. e' `9 d0 t5 m" `1 m
3 D, J0 E: i! b$ L7 b
然后改成支持汉字的
7 a' O) `2 x" f k6 J* c: [把4091d2 的 CMP EDX,0A 改成jmp
' l2 K9 ?* d( [% B' T跳到我的代码上去" o9 P5 f$ W+ m# v* Y- h
% _* A* _, d2 j! z5 ~* ~
AND EDX,0FF 去除高位的FF
4 B: B+ |/ q7 pCMP EDX,0B0 比较是否汉字 跟比较80一样 因为我的字库是从 啊(B0 A1) 开始的
! `7 j7 R$ |( z" A+ EJL Unpacked.004091F8 小于 B0的就跳回去
0 K6 x( E. e$ D- x( m4 L8 aMOV EDX,DWORD PTR SS:[EBP+8]
; Z/ z& Q4 [5 J" r" hMOVSX EAX,WORD PTR DS:[EDX] 取2个字节 (支持汉字)
1 e; ^* c3 l- G- AAND EAX,0FFFF 去除汉字高位的FF# ?( r& r9 v, z' S- ^; ^6 O
MOV DWORD PTR SS:[EBP-40],EAX 存入形参! D7 j, |- ]4 I1 z' g) Y R
LEA ECX,DWORD PTR SS:[EBP-28]
' c9 m4 ?* U5 V( K/ \( cPUSH ECX ; /Arg2
e9 n7 {0 e) T+ u6 s; E3 K1 LMOV EDX,DWORD PTR SS:[EBP-40] ; |6 l# C& f4 S8 L5 _' j0 P- {# F
PUSH EDX ; |Arg1
) z# x8 V- ~: R' `0 [/ V% gMOV ECX,DWORD PTR SS:[EBP-8] ; |1 z/ Y% y, L2 ^) e) Q! K. m6 h; l
CALL Unpacked.007CFF3C 这里是读取并存入 字符串X Y坐标
& G# A% G! q' g+ xMOV EAX,DWORD PTR SS:[EBP+8]
u8 P: P! H* G7 N9 vADD EAX,2 call出来后加2个字节
0 i- f2 l: ~& j: H8 c8 pJMP Unpacked.004092175 Q- v8 s; r$ b. ^. I' E
7 t% h/ p( @5 m. V" }% w0 v$ b5 U8 L7 }3 v) I+ h D
& s2 |! C: t+ k: m
) K2 N. _8 G7 a; x9 `4 |PUSH EBP
. B% F, a& D* Y/ c" [MOV EBP,ESP5 b! b& b( A" j4 c. N$ P" t
SUB ESP,0C
5 `/ b% L! P1 z; v; K, fMOV DWORD PTR SS:[EBP-C],ECX
0 G4 h( w6 C+ h8 BMOV EAX,DWORD PTR SS:[EBP-C]/ F- C/ q0 o0 r, _! ]; e
MOV ECX,DWORD PTR DS:[EAX+14]
, t! p9 _6 x4 s) ]2 JMOV DWORD PTR SS:[EBP-4],ECX
* t! X: f/ k5 d1 c' DCMP DWORD PTR SS:[EBP+8],0F9D7 边界检查 我这里最后个文字是 座(D7 F9)8 D6 }3 @0 y( X. Y* T ]
JG SHORT Unpacked.007CFF8E 超出就绘制一个空白图片/ @% }5 u8 N/ ~7 d
MOV ECX,DWORD PTR SS:[EBP+8] 从形参读取汉字 把汉字 放入ecx (我这里代码写的乱)% k( m9 P1 N# L v+ B$ w
XOR EAX,EAX
3 ]! u0 q2 O: J8 l5 [) VMOV AL,CL 把汉字第一个字节 放入eax; D& h$ w \9 K! H! r1 A e, W1 P
SHR CX,8 右移8位取第二个字节
: @2 j: E# ]; I# } g' vXOR EDX,EDX
u8 n5 l% E' `: G. }2 L6 P# oMOV DL,CL 把第2个字节放到edx去
; P9 d: K% a. h7 X' T( h' k2 H1 h; bSUB AL,0B0 这里是我自己写的算法 不用再读取码表了
7 B' w- P, P& |, OSUB DL,0A1
+ R5 ?, p/ y2 o5 x NIMUL EAX,EAX,10 我用的 宋体16 一个汉字是16X16
- B( |% X% f/ w3 V7 s' YIMUL EDX,EDX,101 v1 R- h7 c# v2 z5 n: z5 z
ADD EAX,20 加上我图片原来的高度( S* B; h5 j# L2 z% c1 y* P
MOV ECX,DWORD PTR SS:[EBP+C]" \9 s" O+ a) b9 k' h
MOV DWORD PTR DS:[ECX],EDX5 }& a4 ?! g" K) u) A0 c, W$ d
MOV DWORD PTR DS:[ECX+4],EAX
q/ S& L2 p1 ^% g; y6 H" q/ B( nADD EAX,10
, L" K" t# v3 s0 w) g, F9 Y) LADD EDX,10
" _. a5 y2 Z/ s3 ~: v# ZMOV DWORD PTR DS:[ECX+8],EDX A0 J# W7 F3 @, |5 K$ I- _. W4 m& ~
MOV DWORD PTR DS:[ECX+C],EAX
/ o& k. Z3 f, b! S OMOV ESP,EBP# V/ A9 O7 I5 G% D
POP EBP
, B% S8 j8 A- B* G0 \$ n8 \: W/ i# ERETN 8
: `1 n3 t# R% y) @1 N. L/ Y( {
: R& f$ H5 ?* \0 Z# y0 g8 D7 G5 M8 {6 t2 G0 F1 r& O" {
|