PacketLength@リプレイ機能が搭載されたROのexeのコードスクランブル

2015年4月19日

 某IRCにて公開していますが、皆さんが一番利用しそうなPacketLengthについて一部抜粋で解説します。
EXEの更新が1度しか行われていないので考察程度に、それぞれ各コード抜粋にジャンプします。

goto 2011_12_01aRagexe 普通にコンパイルしリンカーを通されたコード
goto 2012-8-16data_gm_r_Ragexe パッカーが使われたコード(改修前)
goto 2012-8-21data_gm_r_Ragexe パッカーが使われたコード(改修後、現行exe)

 各コードとも、それぞれ同じカラーでマーキングされた場所が等価コードとなります。マーカーを元に下2つのコードを通常コードと見比べると理解しやすいでしょう。
アドレスを見れば分かりますが、スクランブルされたコードはメモリ上にばらばらに配置されていますが視認性をよくするために繋げて記述しています。
exeには再配置可能な仮想コードが埋め込まれていて実行時にメモリ上に展開されます。アンパックされた状態がスクランブルされたコードなので整形されたコードなんてものは存在しません。

 コードのスクランブルはビルド毎にランダムで、インストラクションレベルでコードの置き換えやランダムジャンプが挿入されるものと推測出来ます。
“e900000000 jmp near (pc+5)"のようなゼロ距離ジャンプが挿入されている場所は、パッカーがコードを分解する際に区切ったもので、別のビルドでコードが分解される可能性があります。

インストラクションレベルで等価な動作(ステップ数や実行サイクルは除外)を行うための命令セットがランダムで置換されます。

例えば

push esi

このコードと

mov dword [esp-004h],esi
lea esp,[esp-004h]

このコードは命令数と実行サイクルが違えど動作は同等です。

サブルーチン等を自動解析エンジンが検索する場合call命令をメモリ上から検索するわけですが、このパッカーはcall命令をstackへのアドレスpushとjmp命令で置換します。

call near function

このコードが

push function_return_subaddress
jmp near function

この様に置き換わる可能性があり、pushは前述のmov & leaで置き換わる可能性があります。
因みに復帰先はワンクッションありjmp専用のサブルーチンが用意されます。これはパッキング処理の都合でしょう。

悩ましいのはピンク色でマークしたコードです。
2012-8-16data_gm_r_Ragexe.exeの抜粋を見ると分かりますが
ただの条件分岐もこのパッカーにかかるとこんな感じです。

要点としてはstackを使ってのアドレス復帰です。
cmovzによる条件付き代入で分岐先をコントロールすることでjz互換命令群としています。ソース上のコメントを見れば理解出来るかと思います。

このようなスクランブルが内部的に重要と思わしきコードへ適応されていて、難読を極めています。
スクランブルする側は、無駄を挿入することでいくらでも複雑に出来ますが、読み解く方は経験則と直感に頼るところがあって、これを自動化することは困難だと考えます。

見ての通りインストラクションキャッシュのミスを誘発するので実行効率は最悪です。

 

CRagConnection::GetPacketSize
;; 2011_12_01aRagexe
CRagConnection__GetPacketSize:
F0065cf90: 0065cf90 83ec10 sub esp,byte +010h
0065cf93 56 push esi
0065cf94 8b742418 mov esi,dword [esp+018h]
0065cf98 8bc6 mov eax,esi
0065cf9a 2dbf020000 sub eax,dword 0000002bfh
0065cf9f 7447 jz C0065cfe8 ; if( opcode == 0x02bf )
0065cfa1 83e801 sub eax,byte +001h
0065cfa4 7436 jz C0065cfdc ; if( opcode == 0x02c0 )
0065cfa6 56 push esi
0065cfa7 8d442408 lea eax,[esp+008h]
0065cfab 50 push eax
0065cfac b944ce8900 mov ecx,dword L0089ce44 ; g_packetLenMap
0065cfb1 e8bab2f2ff call near F00588270 ; g_packetLenMap::InsertTree( eax , esi )
0065cfb6 8bc8 mov ecx,eax
0065cfb8 b802000000 mov eax,dword 000000002h

;; 2012-8-16data_gm_r_Ragexe.exe

CRagConnection__GetPacketSize:
C00872a9e: 00872a9e 83ec10 sub esp,byte +010h
00872aa1 e933541500 jmp near C009c7ed9
C009c7ed9: 009c7ed9 8d6424fc lea esp,[esp-004h] ; *1 push esi
009c7edd 893424 mov dword [esp],esi ; *1
009c7ee0 e900000000 jmp near C009c7ee5
C009c7ee5: 009c7ee5 8b742418 mov esi,dword [esp+018h]
009c7ee9 8bc6 mov eax,esi
009c7eeb 2dbf020000 sub eax,dword 0000002bfh
009c7ef0 e900000000 jmp near C009c7ef5
C009c7ef5: 009c7ef5 68b22a8700 push dword C00872ab2 ; *2 jmp address push C00872ab2
009c7efa e900000000 jmp near C009c7eff
C009c7eff: 009c7eff 51 push ecx ; *2 save ecx
009c7f00 e900000000 jmp near C009c7f05
C009c7f05: 009c7f05 52 push edx ; *2 save edx
009c7f06 8b4c2408 mov ecx,dword [esp+008h] ; *2
009c7f0a bae8d16700 mov edx,dword C0067d1e8 ; *2
009c7f0f 0f44ca cmovz ecx,edx ; *2 jz C0067d1e8
009c7f12 e900000000 jmp near C009c7f17 ; *2
C009c7f17: 009c7f17 894c2408 mov dword [esp+008h],ecx ; *2
009c7f1b 5a pop edx ; *2
009c7f1c 59 pop ecx ; *2
009c7f1d c3 ret ; *2 jmp C00872ab2 or C0067d1e8
C00872ab2: 00872ab2 83e801 sub eax,byte +001h
00872ab5 0f8421a7e0ff jz near C0067d1dc
00872abb e924000000 jmp near C00872ae4
C00872ae4: 00872ae4 8d6424fc lea esp,[esp-004h] ; *1 push esi
00872ae8 893424 mov dword [esp],esi ; *1
00872aeb 8d442408 lea eax,[esp+008h]
00872aef 8d6424fc lea esp,[esp-004h] ; *3 push eax
00872af3 e93c541500 jmp near C009c7f34
C009c7f34: 009c7f34 890424 mov dword [esp],eax ; *3
009c7f37 b9a0358e00 mov ecx,dword L008e35a0 ; g_packetLenMap
009c7f3c 68b6d16700 push dword C0067d1b6 ; *4
009c7f41 e96aa2bdff jmp near C005a21b0 ; *4 call C005a21b0 g_packetLenMap_InsertTree

;; 2012-8-21data_gm_r_Ragexe.exe

CRagConnection__GetPacketSize:
C00872aa2: 00872aa2 83ec10 sub esp,byte +010h
00872aa5 897424fc mov dword [esp-004h],esi ; *0 push esi
00872aa9 e959581500 jmp near C009c8307 ;; goto
C009c8307: 009c8307 8d6424fc lea esp,[esp-004h] ; *0
009c830b 8b742418 mov esi,dword [esp+018h]
009c830f e900000000 jmp near C009c8314 ;; goto
C009c8314: 009c8314 8bc6 mov eax,esi
009c8316 2dbf020000 sub eax,dword 0000002bfh
009c831b 0f84c74ecbff jz near C0067d1e8
009c8321 e994a7eaff jmp near C00872aba ;; goto
C00872aba: 00872aba 83e801 sub eax,byte +001h
00872abd 0f8419a7e0ff jz near C0067d1dc
00872ac3 e91c000000 jmp near C00872ae4 ;; goto
C00872ae4: 00872ae4 897424fc mov dword [esp-004h],esi ; *1 push esi
00872ae8 e948581500 jmp near C009c8335 ;; goto
C009c8335: 009c8335 8d6424fc lea esp,[esp-004h] ; *1
009c8339 8d442408 lea eax,[esp+008h]
009c833d 8d6424fc lea esp,[esp-004h] ; *2 push eax
009c8341 e900000000 jmp near C009c8346 ;; goto
C009c8346: 009c8346 890424 mov dword [esp],eax ; *2
009c8349 b9a0358e00 mov ecx,dword L008e35a0 ; g_packetLenMap
009c834e 68b6d16700 push dword C0067d1b6 ; *3
009c8353 e9589ebdff jmp near C005a21b0 ; *3 call C005a21b0 g_packetLenMap_InsertTree ;; goto

Ragnarok OnlineRagnarok,RO

Posted by redchat