トリトン察花王のおもちゃプロゞェクト。 良い䌝統を続ける







この蚘事では、SMT゜ルバヌに぀いお説明したす。 そのため、このトピックに関する研究資料に良い䌝統が登堎したした。 すでに䜕床か、さたざたな研究者がSMT゜ルバヌの亀裂ず同じ䟋を遞択したした 。これは、ニックネヌムkaoの人が発明した亀裂です。 さお、この䌝統を続けお、蚘号蚈算甚の別のツヌルであるTritonを䜿甚しお亀裂を解決しおみたしょう。







SMT゜ルバヌに関する䞀蚀



理論の公匏の充足可胜性の問題英語の充足可胜性モゞュロ理論、SMTは、それらの基瀎ずなる理論を考慮した論理匏の充足可胜性の問題です。 このようなSMT匏の理論の䟋は次のずおりです。敎数ず実数の理論、リストの理論、配列、ビットベクトルなど- りィキペディア

SMTタスクは、SATタスクの延長ですブヌル充足可胜性問題たたは呜題充足可胜性問題。英語文孊ではSATISFIABILITYたたはSAT、ロシア文孊ではVypず呌ばれるこずもありたす。







りィキペディアからの別の匕甚







SATタスクのむンスタンスは、倉数名、角かっこ、AND、OR、HE挔算のみで構成されるブヌル匏です。 タスクは次のずおりです。匏で発生するすべおの倉数に倀「false」および「true」を割り圓おお、匏がtrueになるようにするこずは可胜ですか。 - りィキペディア

SMT゜ルバヌはさたざたな理論で機胜するため、埓来のプロセッサアヌキテクチャのアルゎリズムにそれらを䜿甚するこずが可胜になりたす。 したがっお、SMT゜ルバヌは2぀の問題を解決できたす。









SMT゜ルバヌは、科孊技術のさたざたな分野で応甚されおいたす。 Z3 、 miniSAT 、 CVC4などのSMT匏を解くための個別のツヌル、およびBAP 、 radare2たたはangrなどのSMT匏の構文で機械語でアルゎリズムを衚すための個別のツヌルがありたす 。 ツヌルは絶えず改善されおおり、APIはより匷力になり、数回クリックするだけでリバヌス゚ンゞニアリングの問題でSMT数孊装眮党䜓を䜿甚できたす。







たた、シンボリックパフォヌマンスにはいく぀かのタむプがあるこずに泚意しおください。 静的シンボリック実行SSEは、シンボリック倉数のみに基づいおおり、シンボリック匏のみを䜿甚したす。 動的シンボリック実行DSEコンコリック実行ずも呌ばれたすは、プログラム実行䞭に数倀倉数の特定の倀ずずもにシンボリック蚈算を䜿甚したす。 このホワむトペヌパヌでは、静的文字の実行のみを䜿甚したす。







花王のトむプロゞェクトクラックストヌリヌ



クラック花王のトむプロゞェクトは非垞にシンプルです。 1぀のりィンドりに、特定の16進数のシヌケンスが衚瀺され、このシヌケンスに有効なキヌの入力が求められたす。













圌の物語は、次の幎代蚘の圢で衚珟できたす。







2012幎3月4日- 花王のおもちゃプロゞェクトず代数暗号解読 -dcoder、andrewl-代数暗号解読、SAT







このクラック専甚の最初の䜜品は2012幎に登堎したした。 その䞭で、ニックネヌムdcoderを持っおいる人が代数暗号解読を䜿甚しお゜リュヌションを公開し、この䜜業の共同著者andrewlがSAT゜ルバヌを正垞に適甚したした。







03/06/2012- シンボリック実行による半自動入力クラフティング、自動キヌゞェネレヌタヌ生成ぞのアプリケヌション -Rolf Rolles-z3、レコヌダヌ







その埌、有名な研究者であるロルフ・ロヌルズは、最初にSMT゜ルバヌを゜リュヌションに適甚したした。 たず、Z3で数匏を手動で䜜成し、次にOCamlでマシンコヌドの䞭間衚珟から数匏を自動的に生成するツヌルを提瀺したした。 圌が䜿甚した䞭間蚀語は自分で開発したした。







BitBlazeずBAPで䜿甚されおいるものず非垞によく䌌たIRを䜿甚しおいたすが、VEXを䜿甚するのではなく、独自のIRトランスレヌタヌを䜜成したした。 私の実装は最初から曞かれおおり、オヌプン゜ヌスのフレヌムワヌクずコヌドを共有したせん。 -openrce.org

11.2013- ゜フトりェアセキュリティ甚のSMT゜ルバヌ -Georgy Nosenko-BAP、z3







その埌、同僚のゞョヌゞ・ノセンコの研究が始たりたした。そこでは、BAPフレヌムワヌクず同じZ3゜ルバヌが既に匏の生成に䜿甚されおいたした。







2015.2015- OpenREILおよびZ3を䜿甚した自動代数暗号解析 -Cr4sh-OpenREIL、z3







Cr4shずしおも知られるDmitry Oleksyukは、圌の研究で、䞭間蚀語OpenREILぞの倉換ず、その埌のZ3での匏の生成を䜿甚したした。







04.2016- シンボリック実行ずangrによる花王のおもちゃプロゞェクトの解決-Extreme Codersブログ-angr







そしお最埌に、2016幎に別の䜜品が登堎し、angrフレヌムワヌクを䜿甚した゜リュヌションに぀いお説明しおいたす。 Angrは、シンボリック実行にVEX䞭間蚀語ずclaripyラむブラリを䜿甚したす。







別のプレむダヌがSMTアリヌナに登堎したした-Triton。この䜜品では、有名なクラックを解決するためにそれを䜿甚したす。







トリトン



TritonはQuarkslabによっお䜜成されたした。Quarkslabは 、リバヌス゚ンゞニアリングのための倚くの興味深いツヌルを䜜成したした。







たず、Tritonの仕組みに぀いお少し説明したす。 圌の仕事の過皋で、圌は次のアクションを実行したす。







  1. バむナリコヌドの実行パスを解析し、機械語呜什のすべおの副䜜甚を考慮した抜象構文コヌドツリヌを生成したす。
  2. 抜象構文ツリヌをバむパスしお、SMT-LIB圢匏のSMT匏を生成したす。
  3. ゜ルバヌz3を䜿甚しお数匏を解きたす。


抜象構文ツリヌを構築する堎合、Tritonはbapやangrずは異なりマシンコヌドの䞭間衚珟を䜿甚せず、珟圚はx86およびx86-64アヌキテクチャでの䜜業のみをサポヌトしおいたす。







Tritonは2぀のモヌドのいずれかで動䜜したす。 最初のオンラむンモヌド-実行トレヌスは、Tritonの䞀郚であり、 ピンDBIフレヌムワヌクを䜿甚する特別なトレヌサヌを䜿甚しお蚘録されたす 。 2番目-オフラむンモヌド-トラックは倖郚手段によっお蚘録されたす。 ルヌトには、䞀連の呜什ずそのオペコヌドが含たれおいる必芁がありたす。 2番目のケヌスでは、初期コンテキストを独立しお䜜成する必芁がありたす。぀たり、レゞスタず䜿甚メモリの倀を決定したす。







Tritonが提䟛するAPIは非垞に豊富で、非垞に䞍安定です。 APIの登堎以来、埌方互換性を維持するこずなく、もちろん4回倉曎されおいたす。 このため、Tritonを䜿甚する叀いツヌルのコヌドは、新しいバヌゞョンで実行するように曞き盎す必芁がありたす。 良い点は、APIにPythonのバむンディングがあるこずです。 リポゞトリには、C ++およびPythonでのAPIの䜿甚方法を瀺すいく぀かの䟋があり、それらを理解するのは非垞に簡単です。







それでは、解決策に取り掛かりたしょう。







解決策



たず、入力されたキヌをチェックするアルゎリズムを芋぀ける必芁がありたす。 コヌドをざっず芋おみるず、生成されたシヌケンスは実際には8぀の32ビット敎数であり、リトル゚ンディアンビュヌではメモリ内に連続しお存圚し、りィンドりではビッグ゚ンディアンずしお衚瀺されおいたす。 キヌの圢匏がXXXXXXXX-XXXXXXXXであるこずがわかりたす。Xは16進数です。 キヌがこの圢匏で入力された堎合、怜蚌手順が呌び出されたす。 これは、IDA Pro逆アセンブラヌの倖芳です。













怜蚌手順では、入力が最初に初期化されたすcipherはリトル゚ンディアンビュヌの32バむトの゜ヌスシヌケンス、String1は倉換埌の出力シヌケンスのバッファヌ、edxおよびebxレゞスタヌは32ビット敎数ずしお衚されるキヌの半分です。 次に、倉換アルゎリズム自䜓xorおよびrol操䜜を䜿甚した32サむクルが続き、String1バッファヌからの結果の文字列が文字列「0how4zdy81jpe5xfu92kar6cgiq3lst7」ず比范されたす。 それらが同䞀である堎合、キヌは有効ず芋なされたす。







したがっお、次のタスクがSMT゜ルバヌに察しお生成されたす。アルゎリズムが実行された埌、edxおよびebxレゞスタのどの入力倀が特定の16進数シヌケンスを登録するかを文字列「0how4zdy81jpe5xfu92kar6cgiq3lst7」に倉換したす。







クラックのあるWindows甚に䜜成されおいるため、TritonトレヌサヌはLinux甚にコンパむルされおいるため動䜜したせん。 もちろん、Windows甚に自分でコンパむルするこずもできたすが、これらはただ冒険です。 したがっお、PythonにはオフラむンモヌドずTritonバむンディングを䜿甚したす。







たず、必芁な定数を玹介したす。







ADDR_CIPHER = 0x4093A8 ADDR_TEXT = 0x409185 ADDR_EBP = 0x18f980 TEXT = "0how4zdy81jpe5xfu92kar6cgiq3lst7" cipher = None
      
      





そしお、初期化を実行したす。







 ctx = TritonContext() ctx.setArchitecture(ARCH.X86) ctx.setConcreteRegisterValue(ctx.registers.ebp, ADDR_EBP) ctx.setConcreteRegisterValue(ctx.registers.esp, 0x18f95b) ctx.setConcreteRegisterValue(ctx.registers.eip, 0x4010ec) ctx.setConcreteMemoryAreaValue(ADDR_CIPHER, cipher) ctx.setConcreteMemoryAreaValue(ADDR_TEXT, list(map(ord, TEXT))) edx = ctx.convertRegisterToSymbolicVariable(ctx.getRegister(REG.X86.EDX)) ebx = ctx.convertRegisterToSymbolicVariable(ctx.getRegister(REG.X86.EBX)) keys = [ctx.convertMemoryToSymbolicVariable(MemoryAccess(ADDR_EBP-0x21, 1)) for i in xrange(32)]
      
      





初期化䞭に、コンテキストを䜜成し、アヌキテクチャを確立し、レゞスタずメモリを初期化し、もちろんシンボル倉数を䜜成したすedxずebxのレゞスタ、および倉換されたシヌケンスのバッファ。匏の制限により倀が課されたす。







次に、実行トレヌスを䜜成したす。 オフラむンモヌドでこれを行うには、バむナリコヌドをダりンロヌドするだけです。







 code = {0x4010EC: '\x55', # push ebp 0x4010ED: '\x8b\xec', # mov ebp, esp 0x4010EF: '\x83\xc4\xdc', # add esp, -24h 0x4010F2: '\xb9\x20\x00\x00\x00', # mov ecx, 20h 0x4010F7: '\xbe\xa8\x93\x40\x00', # mov esi, offset cipher 0x4010FC: '\x8d\x7d\xdf', # lea edi, [ebp+string1] 0x4010FF: '\x8b\x55\x08', # mov edx, [ebp+arg_0] 0x401102: '\x8b\x5d\x0c', # mov ebx, [ebp+arg_4] # loc_401105: 0x401105: '\xac', # lodsb 0x401106: '\x2a\xc3', # sub al, bl 0x401108: '\x32\xc2', # xor al, dl 0x40110A: '\xaa', # stosb 0x40110B: '\xd1\xc2', # rol edx, 1 0x40110D: '\xd1\xc3', # rol ebx, 1 0x40110F: '\xe2\xf4'} # loop loc_401105
      
      





呜什の凊理を開始したす。







 ip = 0x4010ec while ip < 0x401111: inst = Instruction() inst.setOpcode(code[ip]) inst.setAddress(ip) ctx.processing(inst) ip = ctx.buildSymbolicRegister(ctx.registers.eip).evaluate()
      
      





呜什の凊理䞭に、Tritonはそれらを蚘号圢匏に倉換し、受け取った蚘号呜什をコンテキストに远加したす。 このコヌドでは、ipレゞスタのシンボリック゚ミュレヌションを䜿甚しお、実行順に次の呜什を蚈算したす。







この埌、倉数の倀に必芁な制限をコンテキストに導入するこずが残っおいたす。 TEXT定数に配眮した文字列「0how4zdy81jpe5xfu92kar6cgiq3lst7」ず倉換された文字列が等しいかどうかに぀いお、この条件がありたす。







 for i in xrange(32): r_ast = ast.bv(ord(TEXT[i]), 8) l_id = ctx.getSymbolicMemoryId(ADDR_EBP-0x21 + i) l_ast = ctx.getAstFromId(l_id) ex = ast.equal(l_ast, r_ast) expr.append(ex) expr = ast.land(expr)
      
      





制玄は、抜象構文ツリヌASDのノヌドの圢匏で蚭定されたす。 ルヌプでは、文字列の1文字のASDノヌドず、倉換されたシヌケンスの1぀の芁玠のASDノヌドが䜜成されたす。 次に、これら2぀のノヌドを比范する操䜜を含む新しいASDノヌドが䜜成されたす。 すべおの芁玠の等䟡条件は同時に満たされる必芁があるため、サむクルでそれらを受け取った埌、論理AND挔算expr = ast.landexprの䞋で1぀のASDに結合されたす。







すべおが解を蚈算する準備ができおいたす。 指定されたexpr制玄を持぀シンボリック匏のデヌタモデルを取埗したす。







 model = ctx.getModel(expr)
      
      





keygenスクリプト党䜓は、ここから完党にダりンロヌドできたす 。







スクリプトを実行するず...䜕も起こりたせん。 デバッグは、呜什の凊理段階で実行ルヌプが発生するこずを瀺しおおり、ルヌプ呜什が凊理されおいないこずがすぐに明らかになりたす。 トリトンはこの呜什さえ知らないこずが刀明した 。 この問題に察凊する方法は 新しい呜什のセマンティクスをTriton゜ヌスに远加しお再構築できたす。 しかし、Windowsでの再構築はかなり骚の折れる䜜業であるず既に述べたした。 うヌん、すぐに動揺するこずはありたせん。コヌドをやり盎しおください。 ルヌプを実際の動䜜ず同じ呜什セットで眮き換えおみおください。䟋







 dec ecx jz 0401105h
      
      





そしお、手動でルヌプを展開しお、内郚にルヌプのあるブロックではなく、ecxレゞスタに曞き蟌たれおいるルヌプ本䜓32だけを凊理するこずができたす。コヌドは次のようになりたす。







 code = ['\xac', # lodsb '\x2a\xc3', # sub al, bl '\x32\xc2', # xor al, dl '\xaa', # stosb '\xd1\xc2', # rol edx, 1 '\xd1\xc3'] # rol ebx, 1 ctx.setConcreteRegisterValue(ctx.registers.esi, ADDR_CIPHER) ctx.setConcreteRegisterValue(ctx.registers.edi, ADDR_EBP - 0x21) ctx.setConcreteRegisterValue(ctx.registers.eip, 0x401105) ctx.setConcreteMemoryAreaValue(ADDR_CIPHER, cipher) ctx.setConcreteMemoryAreaValue(ADDR_TEXT, list(map(ord, TEXT))) edx = ctx.convertRegisterToSymbolicVariable(ctx.registers.edx) ebx = ctx.convertRegisterToSymbolicVariable(ctx.registers.ebx) ip = 0x401105 for i in xrange(32): for c in code: inst = Instruction() inst.setOpcode(c) inst.setAddress(ip) ctx.processing(inst) ip = ctx.buildSymbolicRegister(ctx.registers.eip).evaluate()
      
      





そこで、新しいオプションを起動したす。 今回は、凊理が完党に実行され、予想どおり、しばらくの間、モデルの蚈算に成功したす。 私たちは埅っおいたす...埅っおいたす...私たちは非垞に長い間埅っおいたした。 埅たなかった。 今回は、問題はモデルを蚈算する機胜であり、ここで゚ラヌを怜出するのはそれほど簡単ではないかもしれたせん。 結果の匏は非垞に倧きく、その蚈算には非垞に長い時間がかかるず想定できたす。 これを確認するために、凊理が行われるルヌプの反埩回数を枛らしたす。 実際、反埩回数が少ないず、結果が出力されたす。 遞択方法を䜿甚するず、実隓甚ラップトップで蚈算に芋える時間がかかる反埩回数の䞊限は12であるこずがわかりたした。はい、非垞に小さく、その増加に䌎い、時間が指数関数的に増加したす。 32回の反埩は12をはるかに超えおおり、C ++でコヌドを曞き換えたずしおも、ずにかく、モデルの蚈算は蚱容できないほど長くなるようです。







getModel関数で非垞に時間がかかるデバッグを調べようずするず、これらはtriton::ast::TritonToZ3Ast::convert



関数の再垰呌び出しであるこずがtriton::ast::TritonToZ3Ast::convert



たす。













ドキュメントに曞かれおいるように、TritonはカスタムASDツリヌを䜿甚したす。







抜象構文朚ASTは、文法を朚ずしお衚珟したものです。 Tritonは、匏にカスタムASTを䜿甚したす。 すべおの匏は実行時に構築されるため、ASTは各プログラムポむントで䜿甚できたす。 -Tritonドキュメント

この関数は、TritonのADSをz3の匏に倉換したす。

TritonのASDを構成する衚珟を芋おみるこずができたす。 モデルを取埗する前に、次の行を远加したす。







 tsym = ctx.getSymbolicExpressions() for ek in sorted(tsym.keys()): e = tsym[ek].getAst() print str(e)
      
      





その埌、次のTriton匏がコン゜ヌルに衚瀺されたす。







 ref!0 = SymVar_0 ref!1 = SymVar_1 ref!2 = SymVar_33 ; Byte reference ref!3 = (concat ((_ extract 31 8) (_ bv0 32)) (_ bv29 8)) ; LODSB operation ref!4 = (ite (= (_ bv0 1) (_ bv0 1)) (bvadd (_ bv4232104 32) (_ bv1 32)) (bvsub (_ bv4232104 32) (_ bv1 32))) ; Index operation ref!5 = (_ bv4198662 32) ; Program Counter ref!6 = (concat ((_ extract 31 8) ref!3) (bvsub ((_ extract 7 0) ref!3) ((_ extract 7 0) ref!1))) ; SUB operation ref!7 = (ite (= (_ bv16 8) (bvand (_ bv16 8) (bvxor ((_ extract 7 

      
      





SMT-LIB構文の匏を取埗するには、別の呌び出しを远加する必芁がありたす。







 print ctx.unrollAst(e)
      
      





この堎所unrollAst



、Tritonの匏からSMT-LIB匏ぞの同じ倉換が行われたすが、ここでもgetModel関数のように完了を埅぀こずはありたせん。

SMT-LIB構文に粟通しおいる人は、Tritonの匏がSSA単䞀静的割り圓おの圢匏のみのSMT-LIB匏であるこずに気付くでしょう。 SMT-LIBには倉数の割り圓お操䜜はありたせん-機胜的なlet挔算子に眮き換えられたす。 しかし、ASDをデプロむせずにTritonの構文をSMT-LIB構文に独立しお倉換し、SSAフォヌムをletステヌトメントに眮き換えおからz3pyにフィヌドしようずするずどうなりたすか かなり面倒で冗長に聞こえたすが、開発者がTritonを完成させるたでこの状況から抜け出す必芁がありたす。







したがっお、結果の匏を䜿甚しお、次のアクションを実行したす。









結果は、Triton構文からSMT-LIB構文ぞの倉換関数です。 もちろん、それは普遍的ではありたせんが、少なくずも私たちの仕事には圹立ちたす。







 def convert(ctx, asserts): zsym = "" tsym = ctx.getSymbolicExpressions() for ek in sorted(tsym.keys()): e = tsym[ek].getAst() if e.getKind() == AST_NODE.VARIABLE: zsym += "(declare-fun ref!%d () (_ BitVec %d))\n" % (ek, e.getBitvectorSize()) nodes = [] for ek in sorted(tsym.keys()): e = tsym[ek].getAst() if e.getKind() <> AST_NODE.VARIABLE: nodes.append("let ((ref!%d %s))" % (ek, e)) # print reduce(lambda x, y: "%s (%s)" % (x, y), reversed(nodes)) def fold(x, y): if not isinstance(y, list): raise TypeError if len(y) == 1: return y[0] return "%s\n(%s)" % (x, fold(y[0], y[1:])) nodes = ["assert"] + nodes nodes[-1] += '\n' + str(asserts) zsym = zsym + '(' + fold(nodes[0], nodes[1:]) + ')' return zsym
      
      





関数の結果は、蚈算のためにz3py゜ルバヌに送信する必芁がありたす。







 s = z3.Solver() cs = z3.parse_smt2_string(expr) s.assert_exprs(cs) s.check() m = s.model() edx, ebx = m.decls()
      
      





珟圚、edxおよびebx倉数には、 z3.z3.FuncDeclRef



クラスのオブゞェクトがz3.z3.FuncDeclRef



たす。 それらの数倀衚珟を取埗し、亀裂内の倉換は互いにけんかした埌に実行されるため、それらをけんかさせる必芁もありたす。







 edx, ebx = m[edx].as_long(), m[ebx].as_long() print "%x-%x" % (edx, edx ^ ebx)
      
      





2番目のバヌゞョンのコヌドはgithubから取埗するこずもできたす。







そのため、亀裂のあるりィンドりの入力フィヌルドにコピヌするだけの行が埗られたす。 手のかゆみはすでにそれをしおいたす。

























やった keygenは正垞に動䜜しおいたす。







ポンセ



Tritonに基づいお、IDA ProのPonceプラグむンずいう別のクヌルなツヌルが構築されたす。 IDA逆アセンブラヌでのシンボリック実行ず汚染分析を盎接行うこずで、非垞に魅力的なこずができたす。 残念ながら、クラック内にルヌプ呜什が存圚するため、Ponceをチェックできたせん。 たぶん、Tritonにルヌプを远加したい人がただいるでしょうか :)たたは、別のオプションがありたす。 kao crackedにはアセンブラの゜ヌスコヌドが付属しおいるため、ルヌプを前述の同様の呜什セットに眮き換えるこずができたす。 その埌、Ponceを䜿甚しおその力を感じるこずが刀明したす。 興味のある読者にずっお、これはクヌルなタスクになりたす。







結論



率盎に蚀っお、トリトンはタスクに察凊したせんでした。 ただし、厳密になりすぎないようにしたしょう。ルヌプステヌトメントは簡単に远加できたす。たた、アセンブリの履歎から刀断するず、開発者は既に反埩凊理を開始しおいたす 。













最新のリバヌス゚ンゞニアリングず、シンボリック実行を䌎わない゜フトりェアの脆匱性の怜玢は過去のものです。 これは、たずえば、DARPAサむバヌグランドチャレンゞ䞭に䜜成された自動脆匱性怜玢および゚クスプロむト生成システムによっお蚌明されたす。 そのため、Tritonなどのツヌルは珟圚倧きな需芁がありたす。 それらが発展するに぀れお、それらはたすたす䜿いやすくなり、その結果、象城的なパフォヌマンスは研究者の仕事においお非垞に手頃で効果的なツヌルになりたす。








All Articles