PtraceのiOSでのデバッグの利用と解読
6060 ワード
デバッガはいったいどのように動作しますか?プロセスattach(マウント)をappにブロックする方法と、これらの保護(いわゆる逆デバッグと逆デバッグ)をどのように解読しますか?
ptraceはシステム呼び出しです.システム呼び出しは何ですか?システムが提供する強力な最下位サービスです.ユーザ層のフレームワークはsystem call上に構築されている.macOS Sierraは約500個のシステム呼び出しを提供している.次のコマンドで、システム上のシステム呼び出しの数を理解します.
コマンドラインで実行:(SIP(system integrity protection)
次に、起動パラメータを削除または変更するとどのような影響を及ぼすかを見てみましょう.削除--reverse-connect 127.0.0.1:63719で何が起こるかを確認し、どのプロセスがdebugserverを起動したかを確認します.
Mac上のコマンドラインアプリケーションを作成し、このようなSwiftコードを実行します.
プログラムが実行されると、ptrace呼び出しが2回スナップされます.
クリックするとptraceが存在するヘッダファイルが表示され、以下のように定義されます.
最初のパラメータはptraceがしなければならないことを示します.2番目のパラメータは、プロセスを操作するPIDを示し、3番目と4番目は最初のパラメータに依存します.上のptraceの出力が見える14は
This request allows a process to gain control of an otherwise unrelated process and begin tracing it. It does not need any cooperation from the to-be-traced process. In this case, pid specifies the process ID of the to-be-traced process, and the other two arguments are ignored.
この情報に基づいて,なぜ最初のptrace呼び出しが発生したのかが分かる.13の
上のコードのコメント行にコメントをキャンセルします:
開発者が逆デバッグの目的を達成するには、
しかし、プロセスがptraceシステム呼び出しをいつ実行したか分からない場合、上記の方法は少し急いでいます.この場合、どのようにデバッグを反転しますか?両者のどちらが優れているかは、後続の文章を見てください.
システムコールについて
ptraceはシステム呼び出しです.システム呼び出しは何ですか?システムが提供する強力な最下位サービスです.ユーザ層のフレームワークはsystem call上に構築されている.macOS Sierraは約500個のシステム呼び出しを提供している.次のコマンドで、システム上のシステム呼び出しの数を理解します.
➜ ~ sudo dtrace -ln 'syscall:::entry' | wc -l
このコマンドは、DTrace
というより強力なツールを使用しています.デバッグの基本--ptrace
コマンドラインで実行:(SIP(system integrity protection)
➜ ~ sudo dtrace -qn 'syscall::ptrace:entry { printf("%s(%d, %d, %d, %d) from %s
", probefunc, arg0, arg1, arg2, arg3, execname); }'
を閉じる必要があることに注意)このコマンドは、ptrace関数が実行されるたびに実行されるDTrace
を作成します.コマンドラインの別のTabで実行されます:➜ ~ lldb -n Finder
この時点でdtraceのtabは出力します:ptrace(14, 283, 0, 0) from debugserver
これはdebugserverという名前のプロセスがptraceを呼び出し、Finderプロセスにattachしたように見えます.しかしdebugserverはどのように呼び出されますか?私たちはLLDBを通じてFinderにattachし、debugserverではありません.また、このdebugserverプロセスはまだ生存していますか?➜ ~ pgrep debugserver
=>43474このプロセスが存在する以上、どのように起動し、どのような起動パラメータがあるかを観察します.➜ ~ ps -fp `pgrep -x debugserver
UID PID PPID C STIME TTY TIME CMD
501 43474 43473 0 4:24PM ttys004 0:00.15 /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/debugserver --native-regs --setsid --reverse-connect 127.0.0.1:63719
cmd: /path/to/debugserver --native-regs --setsid --reverse-connect 127.0.0.1:63719
次に、起動パラメータを削除または変更するとどのような影響を及ぼすかを見てみましょう.削除--reverse-connect 127.0.0.1:63719で何が起こるかを確認し、どのプロセスがdebugserverを起動したかを確認します.
➜ ~ ps -o ppid= $(pgrep -x debugserver)
43473
➜ ~ ps -a 43473
PID TTY TIME CMD
43473 ttys004 0:05.19 /Applications/Xcode.app/Contents/Developer/usr/bin/lldb -n Finder
# LLDB debugserver , debugserver ptrace attach Finder 。
ptraceのパラメータ
Mac上のコマンドラインアプリケーションを作成し、このようなSwiftコードを実行します.
import Foundation
// ptrace(PT_DENY_ATTACH, 0, nil, 0) # ,
while true {
sleep(2)
print("Hello, Ptrace")
}
プログラムが実行されると、ptrace呼び出しが2回スナップされます.
ptrace(14, 45762, 0, 0) from debugserver
ptrace(13, 45762, 5891, 0) from debugserver
クリックするとptraceが存在するヘッダファイルが表示され、以下のように定義されます.
#define PT_TRACE_ME 0 /* child declares it's being traced */
#define PT_READ_I 1 /* read word in child's I space */
#define PT_READ_D 2 /* read word in child's D space */
#define PT_READ_U 3 /* read word in child's user structure */
#define PT_WRITE_I 4 /* write word in child's I space */
#define PT_WRITE_D 5 /* write word in child's D space */
#define PT_WRITE_U 6 /* write word in child's user structure */
#define PT_CONTINUE 7 /* continue the child */
#define PT_KILL 8 /* kill the child process */
#define PT_STEP 9 /* single step the child */
#define PT_ATTACH ePtAttachDeprecated /* trace some running process */
#define PT_DETACH 11 /* stop tracing a process */
#define PT_SIGEXC 12 /* signals as exceptions for current_proc */
#define PT_THUPDATE 13 /* signal for thread# */
#define PT_ATTACHEXC 14 /* attach to running process with signal exception */
#define PT_FORCEQUOTA 30 /* Enforce quota for root */
#define PT_DENY_ATTACH 31
#define PT_FIRSTMACH 32 /* for machine-specific requests */
int ptrace(int _request, pid_t _pid, caddr_t _addr, int _data);
最初のパラメータはptraceがしなければならないことを示します.2番目のパラメータは、プロセスを操作するPIDを示し、3番目と4番目は最初のパラメータに依存します.上のptraceの出力が見える14は
PT_ATTACHEXC
です.man ptrace
で検索して、この具体的な意味を確認できます.This request allows a process to gain control of an otherwise unrelated process and begin tracing it. It does not need any cooperation from the to-be-traced process. In this case, pid specifies the process ID of the to-be-traced process, and the other two arguments are ignored.
この情報に基づいて,なぜ最初のptrace呼び出しが発生したのかが分かる.13の
PT_THUPDATE
については、アップルはこれ以上説明していません.制御プロセス(lldb)が制御プロセス(Xcode runのapp)に伝達されるUnix信号とMachメッセージをどのように処理するかに関係する.デバッグのバックグラウンド方法
上のコードのコメント行にコメントをキャンセルします:
ptrace(PT_DENY_ATTACH, 0, nil, 0)
XcodeのRunが起きるとdebug consoleがこれを印刷していることがわかります:Program ended with exit code: 45
これはXcodeのデフォルトの起動プログラムがlldb attachで同時に使用されているためです.ptrace関数を実行してPT_DENY_ATTACH
パラメータを付けるとlldbは事前に終了し、プログラムは実行を中止します.プログラムを単独で実行しようとすると、後でattachに行くとlldbも失敗し、プログラムは正常に実行されても影響を受けません.多くのMacOSの応用は、この方法で逆デバッグを達成することです.しかし、この方法は非常に解読されやすい.デバッグを逆にする方法
開発者が逆デバッグの目的を達成するには、
ptrace(PT_DENY_ATTACH, 0, 0, 0)
がある場所(ほとんどがmain関数)で実行されるに違いない.だから反デバッグの構想は非常に簡単で、この実行の発生を阻止することです.lldbに-wというオプションがある以上、プロセスの起動を待つには、lldbを使用してプロセスの起動をキャプチャし、プログラムがptraceコマンドを実行する前にPT_DENY_ATTACH
コマンドを変更または無視することができます.コマンドライン実行:➜ ~ sudo lldb -n "helloptrace" -w
.ここでsudoを使うのはlldbのバグのためで、lldbにプロセスの起動を待たせるとsudoを使わないとエラーになります.上記の項目のバイナリファイルを見つけて、コマンドラインにドラッグして実行し、lldbはattachに成功するはずです.➜ ~ sudo lldb -n "helloptrace" -w
(lldb) process attach --name "helloptrace" --waitfor
Process 8336 stopped
* thread #1, stop reason = signal SIGSTOP
frame #0: 0x0000000109522b9a dyld`__ioctl + 10
dyld`__ioctl:
-> 0x109522b9a : jae 0x109522ba4 ;
0x109522b9c : mov rdi, rax
0x109522b9f : jmp 0x109522325 ; cerror
0x109522ba4 : ret
Executable module set to "/Users/gogleyin/Library/Developer/Xcode/DerivedData/helloptrace-bjtaxdebpzdyraaogpbcrihdgwku/Build/Products/Debug/helloptrace".
Architecture set to: x86_64h-apple-macosx.
(lldb) rb ptrace -s libsystem_kernel.dylib
continueが実行を続行すると、ptrace関数が実行されるときに停止します.lldbを使用して、プログラムがその関数を実行しないようにして、事前に戻ることができます:(lldb) thread return 0
continueは実行を続けて、1つの逆デバッグは達成しました!プログラムはptrace関数に入りますが、lldbに関数ロジックが実行されないように早めに戻るように伝えます.に続く
しかし、プロセスがptraceシステム呼び出しをいつ実行したか分からない場合、上記の方法は少し急いでいます.この場合、どのようにデバッグを反転しますか?両者のどちらが優れているかは、後続の文章を見てください.