上次在这翻资料的时候正好看到某人写的虚拟村庄3的汉化教程 手头上正好也有这游戏 所以决定小试下汉化 * ~2 _. P7 S$ d
( D/ J% C! u" _& H0 Z8 O
在汉化前我们需要分析下游戏是如何显示字符串的 是贴图还是点阵 0 I/ x( Q3 W+ N' {7 h. c
这里是用bitblt贴上去的
1 d( E& b- j6 {8 q1 a% U. `5 m+ b. y知道是贴图就要寻找相应的字库和字符串
3 w! d: L4 A. c/ |( I字库在image文件夹就能找到 [3 f" b y' h1 G& L$ u
字符串被压在了EXE里(脱壳后exe增大了3MB)
) J; m0 F4 w- ^( L: j
7 A. P, F$ `3 E: Y; r; a下面就是分析游戏是如何显示字符串的 ' _* \4 K2 f% M$ I6 R1 A5 ~' O7 r# O
用OD载入脱壳后的EXE文件 找到某个字符串下硬件访问 我这里断的是Quit
% r. t" g2 _, M7 q9 C% `; _7 u ) q. w0 T5 w6 c. a# U6 l6 b
按F9启动游戏
% g3 v! n6 h% V+ V2 B! t然后断在4F24D2处' X! I' J# @0 P/ r
这里是读取字符串用的
& O/ c4 ?) q! h% _9 c5 i
$ U8 p0 m, M- v, }) B分析下
; H: h4 M3 t8 L9 z8 y# W6 \004F24D0 |> 8B01 /MOV EAX,DWORD PTR DS:[ECX] 这里是读取4字节 quit
- ?- B" ], F- W% n* D/ J- s% T v004F24D2 |. |BA FFFEFE7E |MOV EDX,7EFEFEFF 这里一块主要分析字符串是否已经到\0
q- U4 c/ C9 O1 M- l004F24D7 |. |03D0 |ADD EDX,EAX Q: g% I, H* K" w6 w
004F24D9 |. |83F0 FF |XOR EAX,FFFFFFFF
( A, J: }0 V' Z* H# d" f004F24DC |. |33C2 |XOR EAX,EDX; A$ V' \3 P; G i
004F24DE |. |83C1 04 |ADD ECX,4 读取后面4个字节9 S, V; R, b+ s, C8 G( W" m/ w
004F24E1 |. |A9 00010181 |TEST EAX,81010100
$ M4 P H6 r- g& z004F24E6 |.^ 74 E8 |JE SHORT Unpacked.004F24D0 如果是4个00(也就是81010100)就跳出) T: t2 L @5 g. N0 X( Z
/ v9 G" e8 v; J+ ]这里要注意一下
8 G# _$ \ Y' f u8 e0 P% X+ p因为是4字节一取 \0处一定要是00 00 00 008 \0 R& Z: x9 y, Z
如果要把Quit
' g+ j& P! E; P! C* c51 75 69 74 00 00 00 00 Quit....Quit....
) o3 d( g3 d/ o1 q' l翻译成"退出吧" 就需要在加4字节
4 t( M( k5 s1 D' P/ a; [2 v( k地方不够用咋办 幸好ecx是个指针 MOV EAX,DWORD PTR DS:[ECX]
8 i. ]$ O6 J4 |: _8 O1 G只要把ecx里的地址改成你的就OK了
8 L! M. \7 u' h5 u2 o7 z2 u$ h# c5 _, ^. e* b" P+ A3 j8 |
继续找处理图片的地方
; j W7 E. }/ m* s一路跟下来到了
- y* V3 U9 m$ c1 w
/ |; A) L/ x O004F398C |. 83E6 F0 AND ESI,FFFFFFF0
3 f- n# g4 R$ y* E# ~004F398F |> 56 PUSH ESI ; /HeapSize = 59 F+ o& K5 d5 y. g
004F3990 |. 6A 00 PUSH 0 ; |Flags = 0& k0 ~6 i% m% D2 y d" y
004F3992 |. FF35 3C7B7B00 PUSH DWORD PTR DS:[7B7B3C] ; |hHeap = 00D60000
7 N d; N1 P: V& }- ~004F3998 |. FF15 14815100 CALL DWORD PTR DS:[<&kernel32.HeapAlloc>>; \HeapAlloc
5 e" o& w) n1 L1 Y004F399E |> 5E POP ESI
0 N( u F' ]4 v. s
4 F* [3 g1 F5 S2 ]3 H) Q" P发现HeapAlloc 这个是用来分配内存的7 B5 N) O2 t; k3 S
F8步过 取eax的地址 就是将写入新的quit的地方
, n7 f5 ^8 l! Y8 l( U0 T! m对其下硬件访问 F9运行
; \$ L. w' T* i7 |3 F% }断在了403811: w: Q. p) Y+ n4 P$ M1 Y( T( O
在F9几次 断在了4091c4
[, P$ C$ _ N& E) c在F9几次 回到了4038116 e8 K Z/ P0 B, B. U) ]
5 G w, F- l" o9 i
确定就是这2处地方了! g- f7 w5 D n- R! m! Q
这里我选择了4091c4 因为在跟踪403811后发现这里的数据没用+ }* h' d* ^- B: y- \* A: v8 J7 H
! J2 Y& B, x) b7 t
004091BE |> 8B55 08 /MOV EDX,DWORD PTR SS:[EBP+8]1 [' v b1 x" u( m
004091C1 |. |0FBE02 |MOVSX EAX,BYTE PTR DS:[EDX] 取第一个字节Q6 J5 J8 X# k! ? L0 e- d8 ~' q2 c4 P
004091C4 |. |85C0 |TEST EAX,EAX
4 o, J# U2 P6 }* w4 d004091C6 |. |0F84 E2000000 |JE Unpacked.004092AE 字符串到达\0就跳出5 J5 k* z3 m. w9 B& Q6 Q: A
004091CC |. |8B4D 08 |MOV ECX,DWORD PTR SS:[EBP+8]
$ G0 k) O9 h2 r/ H' l. a004091CF |. |0FBE11 |MOVSX EDX,BYTE PTR DS:[ECX] 取第一个字节Q
% Z# _9 X q$ z+ L+ k" @! l004091D2 |. |83FA 0A |CMP EDX,0A 判断是否是空格
/ C6 r7 C6 y9 l; V3 _7 \8 X004091D5 |. |75 21 |JNZ SHORT Unpacked.004091F8
2 m, G' |* D- w# D+ R004091D7 |. |8B45 E8 |MOV EAX,DWORD PTR SS:[EBP-18]9 n% c3 p! y4 B- o& Y
004091DA |. |8945 0C |MOV DWORD PTR SS:[EBP+C],EAX: x9 J/ r$ z! v
004091DD |. |6A 00 |PUSH 0 ; /Arg1 = 000000001 ~1 C* v5 D& e1 r$ H1 |- v
004091DF |. |8B4D F8 |MOV ECX,DWORD PTR SS:[EBP-8] ; |% r. W' g: Q( v2 h' _4 l
004091E2 |. |E8 C9A7FFFF |CALL Unpacked.004039B0 ; \Unpacked.004039B0
, Y8 Z/ }% J. B, R0 e* W1 M) \9 ~004091E7 |. |0345 10 |ADD EAX,DWORD PTR SS:[EBP+10], H. c3 [/ w- E
004091EA |. |8945 10 |MOV DWORD PTR SS:[EBP+10],EAX5 e5 Z$ g; d2 K- q
004091ED |. |8B4D 08 |MOV ECX,DWORD PTR SS:[EBP+8]( o! k9 y! \2 U6 e( P0 r
004091F0 |. |83C1 01 |ADD ECX,1& `' N3 A. R+ Q: s) T3 N
004091F3 |. |894D 08 |MOV DWORD PTR SS:[EBP+8],ECX) d6 A" B) {( d S
004091F6 |.^ EB C6 |JMP SHORT Unpacked.004091BE
/ P E+ @) y( a$ d( Y3 I9 m3 u/ H004091F8 |> |8B55 08 |MOV EDX,DWORD PTR SS:[EBP+8] 不是的空格跳到这里# E }. J9 N8 y, q) d+ E# w( M& n
004091FB |. |0FBE02 |MOVSX EAX,BYTE PTR DS:[EDX] 把Q给EAX (实现双字节 就要让他取WORD 这里需要改造), \" ]; ?, W$ r ?- z v9 }6 ]) f
004091FE |. |8945 C0 |MOV DWORD PTR SS:[EBP-40],EAX 把Q 放到参数中去
2 L) a. i! d% t- m) p/ L' P00409201 |. |8D4D D8 |LEA ECX,DWORD PTR SS:[EBP-28]: D4 R8 r v) B+ f+ y+ q
00409204 |. |51 |PUSH ECX ; /Arg2& t K x. C! h) i2 I
00409205 |. |8B55 C0 |MOV EDX,DWORD PTR SS:[EBP-40] ; |3 R. @1 g; f" h! p5 q$ C
00409208 |. |52 |PUSH EDX ; |Arg1 压入Q3 T: t5 ?& v0 |$ f7 i! O+ R
00409209 |. |8B4D F8 |MOV ECX,DWORD PTR SS:[EBP-8] ; |- u9 w9 u9 m7 ^, ?& l
0040920C |. |E8 0FB4FFFF |CALL Unpacked.00404620 ; \Unpacked.00404620 这里是关键
& i! v9 H4 w" {% t( v7 y1 ?00409211 |. |8B45 08 |MOV EAX,DWORD PTR SS:[EBP+8]) G o1 v9 l8 X2 y* ^
00409214 |. |83C0 01 |ADD EAX,1 读完Q后读u
6 d4 Y- F$ {" K& W00409217 |. |8945 08 |MOV DWORD PTR SS:[EBP+8],EAX0 K3 X4 o* o* g; Z2 c
0040921A |. |8D4D D8 |LEA ECX,DWORD PTR SS:[EBP-28]8 r/ N4 a) y6 V# j
0040921D |. |E8 5E8BFFFF |CALL Unpacked.00401D80 这里存入了画Q需要的长度
, O) K( c4 a1 k" b* m8 B: d00409222 |. |8945 D4 |MOV DWORD PTR SS:[EBP-2C],EAX
( h9 _& @. {$ I( G$ X9 E: y) T00409225 |. |837D D4 00 |CMP DWORD PTR SS:[EBP-2C],0
- [6 R: j* j* Q" ?0 |00409229 |. |74 7E |JE SHORT Unpacked.004092A91 K0 r- W1 a+ u% f+ T# i; U
) F) x: \! |* s
" |" Q# w x4 m! Y% S. Y
! N4 \& G9 h1 e. ^+ G1 B
- _6 Y# R/ P( _9 R+ c
$ |8 x" P* G# }+ w+ A, j9 r4 o% @* M4 t) W. Y% |
00404620 /$ 55 PUSH EBP; j' F* N M: R2 R* L
00404621 |. 8BEC MOV EBP,ESP8 [6 W4 o4 p+ Q: `0 r; L" u- r8 g
00404623 |. 83EC 0C SUB ESP,0C7 u5 ?) w/ i" U( l* {
00404626 |. 894D F4 MOV DWORD PTR SS:[EBP-C],ECX 3 [% t7 S7 ^. @: N9 ~& m
00404629 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]. b; u' u' _# F1 f) ?
0040462C |. 8B48 14 MOV ECX,DWORD PTR DS:[EAX+14]
- c+ x" ~( L+ ^/ ]; J! u" R0040462F |. 894D FC MOV DWORD PTR SS:[EBP-4],ECX, h8 O' Y. K1 S$ ~9 Y) c
00404632 |. 837D 08 00 CMP DWORD PTR SS:[EBP+8],0 这里就是边界检查
! C0 {6 m: q) Y' t00404636 |. 7D 0D JGE SHORT Unpacked.00404645
: M- F8 k) l7 S. F! B1 @+ t00404638 |. 8A55 08 MOV DL,BYTE PTR SS:[EBP+8]* H3 [. x1 I: B1 G
0040463B |. 8855 FB MOV BYTE PTR SS:[EBP-5],DL
' ^# Z2 c! E, Y, Y) z5 H0040463E |. 0FB645 FB MOVZX EAX,BYTE PTR SS:[EBP-5]
, W. N7 y: R, e* Z1 ~00404642 |. 8945 08 MOV DWORD PTR SS:[EBP+8],EAX: T" d4 S4 L; j( \2 \; X) v
00404645 |> 817D 08 00010>CMP DWORD PTR SS:[EBP+8],100 边界检查
, t0 r7 Y/ C' k/ X5 S- v, y3 P- C5 }0040464C |. 7D 18 JGE SHORT Unpacked.00404666
9 s6 m1 \3 E; W7 u0040464E |. 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+8]
6 d1 K8 u# d* ~; ]3 y U5 {7 P00404651 |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]" q% s( L+ }/ \) }+ P0 ~
00404654 |. 8B448A 18 MOV EAX,DWORD PTR DS:[EDX+ECX*4+18]
6 U1 e8 z% @2 [% R6 L) P00404658 |. 6BC0 14 IMUL EAX,EAX,14
( r) K1 v( Y* u, ~* G, w4 ?, g0040465B |. 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-C]
. V+ d* z f3 o- _" ~# P1 |$ {0040465E |. 0341 14 ADD EAX,DWORD PTR DS:[ECX+14]
5 H% J6 x" e) p00404661 |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX
1 G8 Y! X% r8 c00404664 |. EB 15 JMP SHORT Unpacked.0040467B
- [5 b! Q4 B1 _. ^9 y: {4 f5 F1 |00404666 |> 8B55 08 MOV EDX,DWORD PTR SS:[EBP+8] 这里一块是算Q的码表
/ ?' N. ?( C8 Y7 n8 o9 R6 b9 Y7 m
9 R8 e% _. G3 }1 J, @0 e0 D4 k! {0 C
. h* X: M# ~; y$ v
0054AA48 51 00 00 00 2D 02 00 00 00 00 00 00 3C 02 00 00 Q...-......<..
% m$ Z7 ]& H; V' s0054AA58 1B 00 00 00 ...
* c! j- A. e) D( u, A1 |' i
6 |& c& U) K/ f q. `51就是字符Q5 ?: \" T( {; T2 ~
2D 02 00 00
4 n" Q# B( N2 h8 p00 00 00 00
6 o6 e% U- F( y$ ^6 q9 F: [2 E: G3C 02 00 00
% t5 H1 E' G4 N- s" ]+ y0 w1B 00 00 00
( n8 U$ I x$ m9 f _% C K: j6 w
3 N) F8 a3 e7 r0 F A━━┓
- }/ c. A) M! F4 q ┃ Q ┃ ( {$ e) |, W, h3 @
┗━━B
: [1 e; B2 B4 ?; F1 h
; P2 n$ s8 |- T) | UA的坐标 (22D,0)( [! I) v8 _: R$ F! O: P$ a
B的坐标 (23C,1B)) R* @6 s" |0 W. I2 s
- v0 e5 _+ f5 Q M6 \/ D. R C
+ }, M I, [6 P& g6 i8 E4 n' V
2 Q4 j5 ^8 S' O4 z
00404669 |. 81E2 FF7F0000 AND EDX,7FFF" a5 ~" g" l$ v; P! K& y2 G i* R1 s; b6 m
0040466F |. 6BD2 14 IMUL EDX,EDX,14
, {+ I& r: ?, P( X& v; W00404672 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]: d" t- r- U( t# j
00404675 |. 0350 14 ADD EDX,DWORD PTR DS:[EAX+14]2 ^* _4 n9 j; o2 e
00404678 |. 8955 FC MOV DWORD PTR SS:[EBP-4],EDX
: {9 {1 |. L& H0040467B |> 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]
; A9 P, s0 C0 f9 z! J/ ~0040467E |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
6 d2 Z+ C0 r4 w; @7 T `0 u! e00404681 |. 8B42 04 MOV EAX,DWORD PTR DS:[EDX+4]
0 C( k: j3 Y# a$ @/ u; `, v+ c00404684 |. 8901 MOV DWORD PTR DS:[ECX],EAX 存入22D
! H, b9 d3 j4 c9 t00404686 |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]
- y! [, ?3 k! y; _00404689 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]( u4 E+ ^9 ^' m( c5 Y& e+ E
0040468C |. 8B42 0C MOV EAX,DWORD PTR DS:[EDX+C]
) j! I! A& F9 M. T5 d8 X# r0040468F |. 8941 08 MOV DWORD PTR DS:[ECX+8],EAX 存入23C# u7 Y! C0 {, i9 V
00404692 |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]6 q6 z" h4 [" L
00404695 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]+ V* i3 u8 S. }5 R7 ], O% }# ^
00404698 |. 8B42 08 MOV EAX,DWORD PTR DS:[EDX+8]5 }# z; L) i* g! H1 u. a# A! ~& |
0040469B |. 8941 04 MOV DWORD PTR DS:[ECX+4],EAX 存入01 f& Q$ j! q/ v8 Y: c; l7 U/ [' ]3 z
0040469E |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]% K) o/ X- b9 c$ f' S7 {. O' v+ U
004046A1 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
! y4 z# g" S- b6 |7 r l004046A4 |. 8B42 10 MOV EAX,DWORD PTR DS:[EDX+10]
! H) S/ n. x/ D004046A7 |. 8941 0C MOV DWORD PTR DS:[ECX+C],EAX 存入1B# o/ h. T4 o5 ]
004046AA |. 8BE5 MOV ESP,EBP
0 M# H$ U# W% k) R004046AC |. 5D POP EBP7 p7 _" o& A2 W
004046AD \. C2 0800 RETN 8
1 D" b/ W3 d; E% ]5 U0 t/ h5 X. [4 J* d7 w8 L
! e( e# }3 Z$ B' b2 e$ Y( ]# I% y2 Q. l. U# q M
* E) V$ H9 ~+ S' ^& o" W* P4 E
, y- z( q& r# H9 N6 q4 h; B$ ?& n知道这些后 就可以改造了
' h9 H( ~0 s6 z% ~: Z先改字库7 h6 E" A" q: X/ f {6 X
# Z) t) m$ I6 @- m6 L/ M X Z
' O0 |1 J* R% G& J$ |! {7 r4 Y
然后改成支持汉字的+ c- v+ q7 H* e
把4091d2 的 CMP EDX,0A 改成jmp
/ t- l) m/ Y, B跳到我的代码上去5 V( z/ x1 I; p. W
8 A. q6 u' r y
AND EDX,0FF 去除高位的FF
8 [+ A* V: t2 R5 |1 `CMP EDX,0B0 比较是否汉字 跟比较80一样 因为我的字库是从 啊(B0 A1) 开始的 c+ @6 v8 a: G: l3 ] b0 Z
JL Unpacked.004091F8 小于 B0的就跳回去
- ?( ~+ E E* QMOV EDX,DWORD PTR SS:[EBP+8]; s8 M! J, s i' U5 h# p7 N
MOVSX EAX,WORD PTR DS:[EDX] 取2个字节 (支持汉字)
) d( \2 R3 l. t# q( r6 vAND EAX,0FFFF 去除汉字高位的FF2 f4 o: L) b( x' {. m3 ~% j
MOV DWORD PTR SS:[EBP-40],EAX 存入形参
! C! m! U k0 G; l5 ]( FLEA ECX,DWORD PTR SS:[EBP-28]) g( v# W4 @$ K" `7 V
PUSH ECX ; /Arg2# |7 F- L0 V; H$ N5 J) R
MOV EDX,DWORD PTR SS:[EBP-40] ; |. K0 f/ A2 n# c! `, u2 o
PUSH EDX ; |Arg1
& G5 C8 f. H* YMOV ECX,DWORD PTR SS:[EBP-8] ; |8 k; _6 r% d' A" Z4 E1 `
CALL Unpacked.007CFF3C 这里是读取并存入 字符串X Y坐标0 S6 ?" @- d1 P2 O# \3 G$ I, ^
MOV EAX,DWORD PTR SS:[EBP+8]( K1 o. |0 b/ P/ `# `4 x
ADD EAX,2 call出来后加2个字节
; L- D) y* y9 f7 m/ D9 eJMP Unpacked.00409217" K' H$ q! j* {- s% z$ s8 N; Q: B
& S; }% }7 C$ W4 @7 @
1 b' E, G7 ~: w5 _. l' m$ E) ]
, n& x( h4 m" ^2 X6 \3 Y7 D
3 K( K; C, J4 K9 J: ~$ @: V* a8 C: wPUSH EBP
& L7 }; b) q! |MOV EBP,ESP
/ j! [' @" h' p( ~' |$ VSUB ESP,0C
# @; U* ~! c, U/ ` a. mMOV DWORD PTR SS:[EBP-C],ECX' V4 D/ V8 b( r$ }
MOV EAX,DWORD PTR SS:[EBP-C]; p5 \" T( v1 I D$ @+ s/ |
MOV ECX,DWORD PTR DS:[EAX+14]
d! e$ ~; ]. @MOV DWORD PTR SS:[EBP-4],ECX
1 x6 a( J7 B; p& k; ]CMP DWORD PTR SS:[EBP+8],0F9D7 边界检查 我这里最后个文字是 座(D7 F9)) ?% m8 }4 V# w" c2 f6 m4 K
JG SHORT Unpacked.007CFF8E 超出就绘制一个空白图片
* ]( h6 P/ ~8 K: q, r, LMOV ECX,DWORD PTR SS:[EBP+8] 从形参读取汉字 把汉字 放入ecx (我这里代码写的乱)
) o, [% L6 k4 xXOR EAX,EAX9 c6 [0 j/ w7 Y/ v% {6 n
MOV AL,CL 把汉字第一个字节 放入eax
- x6 r% u" I8 D* i( v% t! vSHR CX,8 右移8位取第二个字节. _4 K1 y8 y& a K3 Q% K; t8 n
XOR EDX,EDX( y3 r8 R, b: B1 C& t2 t4 C
MOV DL,CL 把第2个字节放到edx去
' ^$ T: h) N/ sSUB AL,0B0 这里是我自己写的算法 不用再读取码表了
' T( C0 c2 Z; X" ^: bSUB DL,0A1; y3 V3 u$ s" G6 u6 s6 O3 Z
IMUL EAX,EAX,10 我用的 宋体16 一个汉字是16X16) {/ r1 l( O( s. \) P/ p2 l
IMUL EDX,EDX,10
" [. I" O' y V/ x$ SADD EAX,20 加上我图片原来的高度
- o/ q% w# f% |) kMOV ECX,DWORD PTR SS:[EBP+C]
) u+ W9 M$ k E; }/ HMOV DWORD PTR DS:[ECX],EDX2 J- G) P0 m7 E) e" G
MOV DWORD PTR DS:[ECX+4],EAX! a2 d3 }1 x) B% Z3 R
ADD EAX,10( d; O6 v8 a1 m& ~; R) Z
ADD EDX,10) @! u/ q" B/ m- x
MOV DWORD PTR DS:[ECX+8],EDX
/ T5 g& S3 C& D' Q& SMOV DWORD PTR DS:[ECX+C],EAX
/ W `7 t+ C2 t B0 lMOV ESP,EBP9 Y( F; i) n& y
POP EBP
+ J. o8 N" c+ m$ X; rRETN 8
v V+ y6 g, i; B. Y
Y, `- F( g7 r6 D2 m4 x7 a4 v
, W, O, M- I. |8 R |