LINEゲームのセキュリティ診断手法
LINE株式会社 セキュリティ室
Kenji Aiko
1
CEDEC 2017
自己紹介
愛甲健二(LINE株式会社)
セキュリティエンジニア:リリース前のWebサービス、
GameのSecurity Riskを調査/判断する仕事
2
自己紹介
愛甲健二(LINE株式会社)
セキュリティエンジニア:リリース前のWebサービス、
GameのSecurity Riskを調査/判断する仕事
3
攻撃者の視点で自社サービスを分析すること
攻撃者の視点(手法)を知ることで、
よりSecureなサービスの提供を行える
• 一般的なチート手法
• Gameの分析
• 対策法
• まとめ
4
• 一般的なチート手法
• Gameの分析
• 対策法
• まとめ
5
Memory Cheat
10
STOP
• Gameを一時的に停止させ、メモリ内で”特定の値”を検索
• SCOREと同じ値を絞り込みにより特定 -> 改変
/proc/<PID>/mem
一般的なチートツールの代表的な機能
Android:
vm_read_overwriteiOS:
Memory
https://github.com/Lazenca/Lazenca-A-Andoird
https://github.com/Lazenca/Lazenca-A-iOS
6
Demo
7
Speed Hack
• Game内時間を加速させてスタミナの回復を早める
• Game速度を遅くしてプレイを簡単にする、など
Game Hacker, Game Guardianといったツールに実装されている
経過時間をClientのみで管理しないことが大事
Server側でも時間をチェックする
8
Demo
9
Local File の改ざん
• Local File内にGame情報を保存(ex: PlayerPerfs of Unity)
• 暗号化されていないため、容易に変更可能
playerprefs.xml
仮に暗号化していたとしても、
Gameファイルを解析すれば復号処理を見つけられる
可能な限りServer側に保持するべき
10
Demo
11
Man-in-the-Middle
Client Server
証明書
すべての通信を取得/改変できる
Proxy
Serverの証明書Proxyの証明書
Serverの公開鍵Proxyの公開鍵
Client Server
Serverの証明書
Serverの公開鍵
Clientに任意の証明書をインストールできるため、
SSLの有無に関係なく、通信は自由に取得/改変できる12
SSL Pinning
Client Server
証明書
Proxy
Serverの証明書Proxyの証明書
Serverの公開鍵Proxyの公開鍵
証明書のチェック
public static bool ValidateServerCertificate (
object sender,
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
string chash = certificate.GetCertHashString ();
if (chash == "(hardcoded hash)")
return true; // SSL certificate check ok
return false;
}
Serverの証明書かどうかを
チェックする
For Unity
13
• 一般的なチート手法
• Gameの分析
• 対策法
• まとめ
14
• 静的解析
• 動的解析
Gameの分析
15
• 静的解析
• 動的解析
Gameの分析
16
静的解析
• Unity (Mono)
• Unity (IL2CPP)
• Cocos2d-x
• Unreal Engine (CPP)
• Unreal Engine (Blueprint)
• dex (Java)
プログラムを動作させずに、機械語(あるいは中間言語)の分析
を行うこと(≒コードリーディング)
17
• Unity (Mono)
• Unity (IL2CPP)
• Cocos2d-x
• Unreal Engine (CPP)
• Unreal Engine (Blueprint)
• dex (Java)
18
GameCode of Unity (Mono)
• ILSpy
– http://ilspy.net/
• JustDecompile
– http://www.telerik.com/products/decompiler.aspx
• dnSpy
– https://github.com/0xd4d/dnSpy
• monodis
– http://www.mono-
project.com/docs/tools+libraries/tools/monodis/
上記ツールを使うことで、
可読性の高いコードに変換(Decompile)できる19
GameCode of Unity (Mono)
assetsbinDataManagedAssembly-CSharp.dll
Assembly-Csharp.dll内にすべてのGameCodeが入っている
• .apkを展開し、Assembly-Csharp.dllをデコンパイルする
• PlayerHealth -> TakeDamageメソッドを表示
20
GameCode of Unity (Mono)
assetsbinDataManagedAssembly-CSharp.dll
ほぼソースコードに戻っている
21
GameCode of Unity (Mono)
assetsbinDataManagedAssembly-CSharp.dll
• ILの編集も可能(Reflexil: http://reflexil.net/)
• dnSpyならメソッドをC#のまま編集できる
対策してない場合、ほぼC#の状態でファイルの編集ができる
22
Demo
23
• Unity (Mono)
• Unity (IL2CPP)
• Cocos2d-x
• Unreal Engine (CPP)
• Unreal Engine (Blueprint)
• dex (Java)
24
GameCode of Unity (IL2CPP)
機械語(ARM/x86)の解析には、
IDAという商用のツールを使う(無料版はx86のみ対応)
https://www.hex-rays.com/
https://blogs.unity3d.com/jp/2015/05/06/an-introduction-to-ilcpp-internals/
• ILからCPPのコードに変換され、機械語(ARM/x86)になる
• Gameファイル内の.so(ARM/x86)を解析する必要がある
25
GameCode of Unity (IL2CPP)
assetsbinDataManagedAssembly-CSharp.dll
もともとのソースコード
26
.text:004855FC PlayerHealth$$TakeDamage
.text:004855FC STMFD SP!, {R4,R10,R11,LR}
.text:00485600 ADD R11, SP, #8
.text:00485604 MOV R4, R0
.text:00485608 MOV R0, #1
.text:0048560C STRB R0, [R4,#0x45]
.text:00485610 LDR R0, [R4,#0x10]
.text:00485614 SUB R1, R0, R1
.text:00485618 STR R1, [R4,#0x10]
.text:0048561C LDR R0, [R4,#0x14]
.text:00485620 CMP R0, #0
.text:00485624 BEQ loc_485680
.text:00485628 VMOV S0, R1
.text:0048562C LDR R2, [R0]
.text:00485630 VCVT.F32.S32 S0, S0
.text:00485634 LDR R3, [R2,#0x22C]
.text:00485638 LDR R2, [R2,#0x230]
.text:0048563C VMOV R1, S0
.text:00485640 BLX R3
.text:00485644 LDR R0, [R4,#0x38]
.text:00485648 CMP R0, #0
.text:0048564C BEQ loc_485680
.text:00485650 MOV R1, #0
.text:00485654 BL AudioSource$$Play_0
.text:00485658 LDR R0, [R4,#0x10]
.text:0048565C CMP R0, #0
.text:00485660 LDMGTFD SP!, {R4,R10,R11,PC}
.text:00485664 LDRB R0, [R4,#0x44]
.text:00485668 CMP R0, #0
.text:0048566C BEQ loc_485674
.text:00485670 LDMFD SP!, {R4,R10,R11,PC}
.text:00485674 loc_485674
.text:00485674 MOV R0, R4
.text:00485678 LDMFD SP!, {R4,R10,R11,LR}
.text:0048567C B PlayerHealth$$Death
.text:00485680 loc_485680
.text:00485680 BL loc_52DF78
.text:00485684 MOV LR, PC
.text:00485688 B loc_48D21C
.text:0048568C EnemyHealth$$_ctor
.text:0048568C MOV R1, #0x64
.text:00485690 MOV R2, #0xA
.text:00485694 STR R1, [R0,#0xC]
.text:00485698 MOV R1, #0x40200000
.text:004856A0 STR R1, [R0,#0x14]
.text:004856A4 MOV R1, #0
.text:004856A8 STR R2, [R0,#0x18]
.text:004856AC B MonoBehaviour$$_ctor
.text:004856AC ; End of function PlayerHealth$$TakeDamage
IDA
27
Demo
28
• Unity (Mono)
• Unity (IL2CPP)
• Cocos2d-x
• Unreal Engine (CPP)
• Unreal Engine (Blueprint)
• dex (Java)
29
GameCode of Cocos2d-x
Touch
Count up
bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
{
g_counter += 1;
label->setString(StringUtils::format("%d", g_counter));
if (200000000 <= g_counter) {
label1->setString("Thank you for counting up!");
}
return true;
} HelloWorldScene.cpp
30
.text:0012BAF8 ; _DWORD __fastcall HelloWorld::onTouchBegan(
HelloWorld *__hidden this, cocos2d::Touch *, cocos2d::Event *)
.text:0012BAF8
.text:0012BAF8 var_30= -0x30
.text:0012BAF8 var_2C= -0x2C
.text:0012BAF8 var_24= -0x24
.text:0012BAF8 var_20= -0x20
.text:0012BAF8 var_1C= -0x1C
.text:0012BAF8
.text:0012BAF8 MOVS R1, #0xB0
.text:0012BAFA PUSH {R4-R7,LR}
.text:0012BAFC LDR R6, =(__stack_chk_guard_ptr - 0x12BB06)
.text:0012BAFE LDR R4, =(g_counter_ptr - 0x12BB0A)
.text:0012BB00 SUB SP, SP, #0x1C
.text:0012BB02 ADD R6, PC ; __stack_chk_guard_ptr
.text:0012BB04 LDR R6, [R6] ; __stack_chk_guard
.text:0012BB06 ADD R4, PC ; g_counter_ptr
.text:0012BB08 LDR R4, [R4] ; g_counter
.text:0012BB0A LDR R3, [R6]
.text:0012BB0C LSLS R1, R1, #2
.text:0012BB0E ADD R5, SP, #0x30+var_20
.text:0012BB10 STR R3, [SP,#0x30+var_1C]
.text:0012BB12 LDR R3, [R4]
.text:0012BB14 MOVS R0, R5; this
.text:0012BB16 ADDS R2, R3, #1
.text:0012BB18 LDR R3, =(label_ptr - 0x12BB20)
.text:0012BB1A STR R2, [R4]
.text:0012BB1C ADD R3, PC ; label_ptr
.text:0012BB1E LDR R3, [R3] ; label
.text:0012BB20 LDR R7, [R3] 31
.text:0012BB22 LDR R3, [R7]
.text:0012BB24 LDR R3, [R3,R1]
.text:0012BB26 LDR R1, =(aD - 0x12BB2E)
.text:0012BB28 STR R3, [SP,#0x30+var_30]
.text:0012BB2A ADD R1, PC; "%d"
.text:0012BB2C BL j_j__ZN7cocos2d11StringUtils6formatEPKcz
; j_cocos2d::StringUtils::format(char const*,...)
.text:0012BB30 MOVS R3, #0x2C0
.text:0012BB34 STR R3, [SP,#0x30+var_2C]
.text:0012BB36 MOVS R0, R7
.text:0012BB38 MOVS R1, R5
.text:0012BB3A LDR R3, [SP,#0x30+var_30]
.text:0012BB3C BLX R3
.text:0012BB3E MOVS R0, R5
.text:0012BB40 BL sub_4BB420
.text:0012BB44 LDR R2, [R4]
.text:0012BB46 LDR R3, =0xBEBC1FF
.text:0012BB48 CMP R2, R3
.text:0012BB4A BLE loc_12BB72
.text:0012BB4C LDR R3, =(label1_ptr - 0x12BB56)
.text:0012BB4E LDR R2, [SP,#0x30+var_2C]
.text:0012BB50 LDR R1, =(aThankYouForCou - 0x12BB5A)
.text:0012BB52 ADD R3, PC ; label1_ptr
.text:0012BB54 LDR R3, [R3] ; label1
.text:0012BB56 ADD R1, PC; "Thank you for counting up!"
.text:0012BB58 MOVS R0, R5
.text:0012BB5A LDR R4, [R3]
.text:0012BB5C LDR R3, [R4]
.text:0012BB5E LDR R7, [R3,R2]
.text:0012BB60 ADD R2, SP, #0x30+var_24 32
.text:0012BB62 BL sub_4BD944
.text:0012BB66 MOVS R0, R4
.text:0012BB68 MOVS R1, R5
.text:0012BB6A BLX R7
.text:0012BB6C MOVS R0, R5
.text:0012BB6E BL sub_4BB420
.text:0012BB72 loc_12BB72 ; CODE XREF: HelloWorld::onTouchBegan(
cocos2d::Touch *,cocos2d::Event *)+52
.text:0012BB72 LDR R2, [SP,#0x30+var_1C]
.text:0012BB74 LDR R3, [R6]
.text:0012BB76 MOVS R0, #1
.text:0012BB78 CMP R2, R3
.text:0012BB7A BEQ loc_12BB8C
.text:0012BB7C BL j_j___stack_chk_fail
.text:0012BB80 B loc_12BB82
.text:0012BB82 loc_12BB82; CODE XREF: HelloWorld::onTouchBegan(
cocos2d::Touch *,cocos2d::Event *)+88
.text:0012BB82 MOVS R0, R5
.text:0012BB84 BL sub_4BB420
.text:0012BB88 BL __cxa_end_cleanup
.text:0012BB8C
.text:0012BB8C loc_12BB8C; CODE XREF: HelloWorld::onTouchBegan(
cocos2d::Touch *,cocos2d::Event *)+82
.text:0012BB8C ADD SP, SP, #0x1C
.text:0012BB8E POP {R4-R7,PC}
libMyGame.so33
.text:0012BB46 LDR R3, =0xBEBC1FF
.text:0012BB48 CMP R2, R3
.text:0012BB4A BLE loc_12BB72
.text:0012BB4C LDR R3, =(label1_ptr - 0x12BB56)
.text:0012BB4E LDR R2, [SP,#0x30+var_2C]
.text:0012BB50 LDR R1, =(aThankYouForCou - 0x12BB5A)
.text:0012BB52 ADD R3, PC ; label1_ptr
.text:0012BB54 LDR R3, [R3] ; label1
.text:0012BB56 ADD R1, PC; "Thank you for counting up!"
.text:0012BB58 MOVS R0, R5
.text:0012BB5A LDR R4, [R3]
.text:0012BB5C LDR R3, [R4]
.text:0012BB5E LDR R7, [R3,R2]
.text:0012BB60 ADD R2, SP, #0x30+var_24
.text:0012BB62 BL sub_4BD944
.text:0012BB66 MOVS R0, R4
.text:0012BB68 MOVS R1, R5
.text:0012BB6A BLX R7
.text:0012BB6C MOVS R0, R5
.text:0012BB6E BL sub_4BB420 libMyGame.so
if (200000000 <= g_counter) {
label1->setString("Thank you for counting up!");
} HelloWorldScene.cpp34
signed int __fastcall HelloWorld::onTouchBegan(HelloWorld *this,
cocos2d::Touch *a2, cocos2d::Event *a3)
{
++g_counter;
v3 = label;
v4 = *(void (__fastcall **)(int, char *))(*(_DWORD *)label + 704);
j_cocos2d::StringUtils::format((cocos2d::StringUtils *)&v9, "%d");
v4(v3, &v9);
sub_4BB420(&v9);
if ( g_counter > 199999999 )
{
v5 = label1;
v6 = *(void (__fastcall **)(int, char *))(*(_DWORD *)label1 + 704);
sub_4BD944(&v9, "Thank you for counting up!", &v8);
v6(v5, &v9);
sub_4BB420(&v9);
}
result = 1;
if ( v10 != _stack_chk_guard )
j_j___stack_chk_fail(1);
return result;
} libMyGame.so
35
• Unity (Mono)
• Unity (IL2CPP)
• Cocos2d-x
• Unreal Engine (CPP)
• Unreal Engine (Blueprint)
• dex (Java)
36
GameCode of UE4
Unreal Engine4 はCPPとBlueprintでGameCodeを書ける
• CPP
– libUE4.soにGameEngineと共にGameCodeも入る
– アセンブラのためIDAで解析できる
• Blueprint
– main.obb.png(*.pak)にGameCodeが入る
– 独自の中間言語(?)が入っている
37
GameCode of UE4(CPP)
libarmeabi-v7alibUE4.so
38
GameCode of UE4(CPP)
libarmeabi-v7alibUE4.so
libUE4.soにはGameEngineといっしょにGameCodeも入っている
(サイズが大きいためIDAの読み込みに時間がかかる)39
• Unity (Mono)
• Unity (IL2CPP)
• Cocos2d-x
• Unreal Engine (CPP)
• Unreal Engine (Blueprint)
• dex (Java)
40
GameCode of UE4(Blueprint)
Blueprintは、UE4のVisual Scripting System
視覚的なブロックを組み合わせてプログラミングが行える
https://www.unrealengine.com/marketplace/blueprint-quick-time-events?lang=ja
Blueprintで書かれたコードは、
apk内の assetsmain.obb.png に保存されている
(PCビルドだと*.pakがすでにある)41
1. main.obb.png を zip展開
2. [GameName]ContentPaks*.pakを取得
3. u4pak.pyで*.pakを展開
– https://github.com/panzi/u4pak
4. *.uasset, *.uexpにGameCodeが存在する
完全に対応したデコンパイラが見当たらないため、
IL, Javaバイトコードのようにはいかない
Main.obb.png folder
ZIP展開
*.pak
u4pak.py展開
folder
*.uasset
*.uexp
GameCode of UE4(Blueprint)
42
• Unity (Mono)
• Unity (IL2CPP)
• Cocos2d-x
• Unreal Engine (CPP)
• Unreal Engine (Blueprint)
• dex (Java)
43
dex (Java)
44
Java Decompiler: http://jd.benow.ca/
$ apktool d –r –o $1 $1.apk
$ java –jar smali.jar –o $1/classes.dex $1/smali/
$ sh dex2jar-2.1/d2j-dex2jar.sh $1/classes.dex
*.jar
GameCodeそのものがJavaで書かれていることは少ない
ただし、Androidアプリの基礎言語なので知っておいた方がよい
• 静的解析
• 動的解析
Gameの分析
45
動的解析
Program
Debugger
コードの解析(Debug)
プログラムを動作させながら、機械語(あるいは中間言語)の分析
を行うこと(≒デバッグ)
46
動的解析
端末
PC
game
gdb
$ gdbserver tcp:9090 –attach [pid]
$ gdb
(gdb) target remote 1.1.1.1:9090
0xb7704923 in ?? ()
(gdb)
コードの解析(Debug)
Gameをプレイ(デバッグ)しながら、
各ステップ命令ごとの動作を確認する
プログラムを動作させながら、機械語(あるいは中間言語)の分析
を行うこと(≒デバッグ)
47
動的解析
端末
PC
game
gdb
$ gdbserver tcp:9090 –attach [pid]
$ gdb
(gdb) target remote 1.1.1.1:9090
0xb7704923 in ?? ()
(gdb)
Burp
PC GameServer
通信の解析
コードの解析(Debug)
実際には通信もキャプチャし、
“どのタイミングで通信が発生したか”なども調べる
プログラムを動作させながら、機械語(あるいは中間言語)の分析
を行うこと(≒デバッグ)
48
動的解析
.text:004855FC PlayerHealth$$TakeDamage
.text:004855FC STMFD SP!, {R4,R10,R11,LR}
.text:00485600 ADD R11, SP, #8
.text:00485604 MOV R4, R0
.text:00485608 MOV R0, #1
.text:0048560C STRB R0, [R4,#0x45]
.text:00485610 LDR R0, [R4,#0x10]
.text:00485614 SUB R1, R0, R1
.text:00485618 STR R1, [R4,#0x10]
.text:0048561C LDR R0, [R4,#0x14]
.text:00485620 CMP R0, #0
.text:00485624 BEQ loc_485680
.text:00485628 VMOV S0, R1
.text:0048562C LDR R2, [R0]
.text:00485630 VCVT.F32.S32 S0, S0
.text:00485634 LDR R3, [R2,#0x22C]
.text:00485638 LDR R2, [R2,#0x230]
.text:0048563C VMOV R1, S0
.text:00485640 BLX R3
.text:00485644 LDR R0, [R4,#0x38]
.text:00485648 CMP R0, #0
.text:0048564C BEQ loc_485680
.text:00485650 MOV R1, #0
.text:00485654 BL AudioSource$$Play_0
.text:00485658 LDR R0, [R4,#0x10]
.text:0048565C CMP R0, #0
.text:00485660 LDMGTFD SP!, {R4,R10,R11,PC}
.text:00485664 LDRB R0, [R4,#0x44]
.text:00485668 CMP R0, #0
.text:0048566C BEQ loc_485674
.text:00485670 LDMFD SP!, {R4,R10,R11,PC}
.text:00485674 loc_485674
.text:00485674 MOV R0, R4
.text:00485678 LDMFD SP!, {R4,R10,R11,LR}
.text:0048567C B PlayerHealth$$Death
.text:00485680 loc_485680
.text:00485680 BL loc_52DF78
.text:00485684 MOV LR, PC
.text:00485688 B loc_48D21C
.text:0048568C EnemyHealth$$_ctor
.text:0048568C MOV R1, #0x64
.text:00485690 MOV R2, #0xA
.text:00485694 STR R1, [R0,#0xC]
.text:00485698 MOV R1, #0x40200000
.text:004856A0 STR R1, [R0,#0x14]
.text:004856A4 MOV R1, #0
.text:004856A8 STR R2, [R0,#0x18]
.text:004856AC B MonoBehaviour$$_ctor
.text:004856AC ; End of function PlayerHealth$$TakeDamage
break
実行時の状態を解析できる
• レジスタの状態
• メモリの状態
• スタックトレース
通信データの復号処理直後のメモリを
確認すれば、平文が得られる
CMP R0, #0 CMP R0, #1
動的に命令を変えて処理を観察
動的に変わる状態を
分析できる
49
Demo
50
動的解析
任意のメソッドのcall logを出したり、動作そのものを変えられる
(いわゆるAPI Hookと同じ仕組み)
Xposed:
http://repo.xposed.info/module/de.robv.android.xposed.installer
FRIDA:
https://www.frida.re/docs/android/
Cydia Substrate:
http://www.cydiasubstrate.com/
動的に命令を書き換えて、
処理をHookするFrameworkもある
51
• 一般的なチート手法
• Gameの分析
• 対策法
• まとめ
52
対策法
• 難読化
– 意図的にコードを難しくする
• 暗号化
– ファイルを暗号化しておき、実行時に復号する
静的解析の対策
53
難読化の例
Unityの*.dllをAppFuscatorで難読化
Game実行に問題はないが、デコンパイルしても可読性は低い
AppFuscator: http://appfuscator.com/54
暗号化の例
Assembly-CSharp.dll
https://github.com/Unity-Technologies/mono
mono/metadata/image.c
MonoImage *
mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy,
MonoImageOpenStatus *status, gboolean refonly, const char *name)
{
MonoCLIImageInfo *iinfo;
MonoImage *image;
char *datac;
// add DLL decrypt code
if (name != NULL && strstr(name, "Assembly-CSharp.dll")) {
// decrypt code
for(int i=0; i < data_len; i++) { data[i] ^= 0xFF; }
} 55
UnityPlayerActivity.java
→ onCreate ()
→ new UnityPlayer ()
→ System.loadLibrary (“libmain.so”); # in Static initializer
libmain.so
→ JNI_Onload ()
→ NativeLoader.load, unload <-> load, unload in libmain.so
Unity起動処理
→ NativeLoader.load(); # in Constructor of UnityPlayer
libmain.so
→ load “libmono.so” and “libunity.so”
libunity.so
→ JNI_Onload ()
→ NativeXXX <-> UnityPlayer
→ load “libil2cpp.so”
→ load *.dll
libmono.so 復号処理を追加
暗号化済み56
Cocos2dxActivity.java
→ onCreate ()
→ init ()
→ new Cocos2dxRenderer ()
→ onSurfaceCreated ()
→ nativeInit ()
javaactivity-android.cpp (libMyGame.so)
→ Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit ()
→ onLoadNativeLibraries ()
→ cocos2d::Application::getInstance()->run();
CCApplication-android.cpp (libMyGame.so)
→ applicationDidFinishLaunching ()
Classes/AppDelegate.cpp (libMyGame.so)
→ System.loadLibrary (“android.app.lib_name”);
javaactivity-android.cpp (libMyGame.so)
→ JNI_Onload ()
→ cocos_android_app_init ()
proj.android/jni/hellocpp/main.cpp (libMyGame.so)
Cocos2d-x起動処理
57
対策法
• 難読化
– 意図的にコードを難しくする
• 暗号化
– ファイルを暗号化しておき、実行時に復号する
静的解析の対策
コードの可読性を下げたり、
GameCode以外の部分も解析しなければならないように
コードを追加/変更する
58
対策法
• プロセスの保護
– デバッガからのAttachを検知する
• メモリ内容のエンコード or 暗号化
– メモリ内のDataは使用する直前に復号/暗号化する
動的解析の対策
プロセスを保護する手法が一般的
ただし、root権限からプロセスを完全に守るのは不可能
Gameそのものの安定性を阻害する原因にもなりうる
59
対策法
Client側でGameの処理をしている以上、100%の対策は不可能
• Server側でClientのログを分析する
– 不正ユーザーの多くはログを分析することで検知可能
• すべてをServer側に置く設計にする
– ブラウザベースのゲーム、クラウドゲームなど
60
クラウドゲーム(Cloud gaming)
入力情報
入力情報をそのまま送信
Client Server
動画、音声を返す
input
output
• Clientは”入力受け取り”と”動画再生”のみを担う
• Clientを分析してもチート行為はできない
• リアルタイム画像分析によるBot行為は可能
構造的にゲームの不正行為ができない仕組み
61
Game における Security Risk
1. 悪意あるPlayerが攻略を簡略化できるもの
2. 悪意あるPlayerが他Playerに被害を与えられるもの
本当にマズいのは 2. であるため、
仮にGameプロトコルを解析されたとしても、
他Playerに直接影響が出ないように設計するべき
62
対策法
Client側でGameの処理をしている以上、100%の対策は不可能
• Server側でClientのログを分析する
– 不正ユーザーの多くはログを分析することで検知可能
• すべてをServer側に置く設計にする
– ブラウザベースのゲーム、クラウドゲームなど
• 他Playerに被害が及ばない設計にする
63
• 一般的なチート手法
• Gameの分析
• 対策法とその仕組み
• まとめ
64
まとめ
• ツール対策はしておきたい
– ツールを使えば簡単にCheatできるのは阻止したい
• 時間をかければ必ず解析できる
– 費用対効果を考えてセキュリティ対策を
– Server側で調査できるようにログをとっておくなど
• 解析されたとしても安全な設計を
– 無関係のPlayerに被害が及ぶのはよろしくない
– Server側の脆弱性が露見するなど
65
References
66
mono-project
http://www.mono-project.com/
CIL
http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf
An introduction to IL2CPP internals
https://blogs.unity3d.com/jp/2015/05/06/an-introduction-to-ilcpp-internals/
cocos2d-xでAndroidの起動シーケンスを追いかけてみる
http://qiita.com/yosizo@github/items/53c74f0267becd6a81df
[Unity/C#]WWW/HttpWebRequestにおける中間者攻撃の危険性を考慮した通信プログラムまとめ
http://qiita.com/harmegiddo/items/b72ca4f430292251c8a6
DeNAtechcon_DeNAのセキュリティの取り組みと、スマートフォンセキュリティ
https://www.slideshare.net/harupu/denatechcondenasameorigin-policy
スマートフォンゲームのチート事情
https://www.slideshare.net/ssuser8200d3/ss-59926328
セキュリティエンジニアからみたUnityのこと
https://engineering.linecorp.com/ja/blog/detail/110
Unityゲーム開発 オンライン3Dアクションゲームの作り方
https://www.amazon.co.jp/dp/B00QJINRHK
作れる! 学べる! Unreal Engine 4 ゲーム開発入門
https://www.amazon.co.jp/dp/4798149373
References
67
Unity
https://unity3d.com
Cocos2d-x
http://www.cocos2d-x.org/
Unreal Engine 4
https://www.unrealengine.com
IDA
https://www.hex-rays.com/
apktool
https://ibotpeaches.github.io/Apktool/
dex2jar
https://sourceforge.net/projects/dex2jar/
AppFuscator
http://appfuscator.com/
Unity Technologies mono
https://github.com/Unity-Technologies/mono
Unity metadata loader
https://github.com/kenjiaiko/unity_metadata_loader
https://github.com/nevermoe/unity_metadata_loader
Thank you!
68
[CEDEC2017] LINEゲームのセキュリティ診断手法

[CEDEC2017] LINEゲームのセキュリティ診断手法

Editor's Notes

  • #2 CEDECの方に資料は公開します。
  • #4 このセッションでは、攻撃者の視点で、Gameを分析/チートする手法を紹介、解説します。
  • #7 Rootがあれば任意のプロセスのメモリにアクセスできる。
  • #13 SSLが保証しているのは、通信経路上のみでの暗号の安全性。 攻撃者がクライアントも保持している場合は、その限りではない。極端な話、game内メモリには復号されたデータが存在する。
  • #14 証明書をチェックして、ゲーム内容を変更できる。 仮に指定したServer以外の証明書だった場合は、ゲームを強制的に終了する、など。
  • #21 これはUnityのsample tutorialのsurvival Shooterをビルドしたapkをunpackしたものです。 Unityで作成したapkは、zip展開すると、assets\bin\Data\Managed\Assembly-Csharp.dllにgameコードが入っている
  • #36 IDAにはデコンパイルの機能もあります。 完全なソースコードに復元することはできませんが、それなりに可読性の高いものにできます。
  • #43 ただし、重力の値や、関数、メソッドのようなものは確認できるため、改ざんも難しくない。
  • #49 Burp https://portswigger.net/burp Webアプリケーションの診断ツール 一般的にはブラウザとサーバの中間に入って通信内容をキャプチャ/変更するツールだが、 Gameの分析にも使用できる。
  • #50 Burp https://portswigger.net/burp
  • #53 プロセスに任意のコードを追加して、特定のコードを制御する。 ゲームファイルそのものを変える必要がなく、 特定のメソッドに対して、処理を追加したり、省略できる。