Files
2023-03-04 14:44:58 -06:00

203 lines
6.8 KiB
C#

using Dna.Binary.Windows;
using Dna.ControlFlow;
using Dna.ControlFlow.Analysis;
using Dna.Emulation;
using Dna.Lifting;
using Dna.Optimization;
using Dna.Optimization.Passes;
using Dna.Relocation;
using Dna.Synthesis.Jit;
using Dna.Synthesis.Miasm;
using Dna.Synthesis.Parsing;
using Dna.Synthesis.Simplification;
using Dna.Synthesis.Utils;
using DotNetGraph.Extensions;
using Rivers;
using Rivers.Analysis;
using System.Diagnostics;
using Grpc.Net.Client;
using TritonTranslator.Arch;
using TritonTranslator.Arch.X86;
using ClangSharp.Interop;
using ClangSharp;
using Dna.Decompiler;
using Dna.Emulation.Unicorn;
using Dna.Decompilation;
using Dna.Structuring.Stackify;
// Load the 64 bit PE file.
// Note: This file is automatically copied to the build directory.
var path = @"C:\Users\Public\Documents\VMProtect\Code Markers\MSVC\x64\Release\Project1.vmp.exe";
var binary = new WindowsBinary(64, File.ReadAllBytes(path));
// Instantiate dna.
var dna = new Dna.Dna(binary);
// Parse a (virtualized) control flow graph from the binary.
ulong funcAddr = 0x14000177E;
var cfg = dna.RecursiveDescent.ReconstructCfg(funcAddr);
// The VM entry spans across multiple routines. To avoid disassembling multiple
// control flow graphs, we selectively insert instructions needed to have a
// correct CFG for the entirety of the vm entry.
var target = cfg.GetBlocks().First();
target.Instructions.Insert(0, dna.BinaryDisassembler.GetInstructionAt(0x14000177E));
target.Instructions.Insert(1, dna.BinaryDisassembler.GetInstructionAt(0x140001783));
target.Instructions.Insert(2, dna.BinaryDisassembler.GetInstructionAt(0x140001789));
target.Instructions.Insert(3, dna.BinaryDisassembler.GetInstructionAt(0x14000178F));
target.Instructions.Insert(4, dna.BinaryDisassembler.GetInstructionAt(0x140001794));
target.Instructions.Insert(5, dna.BinaryDisassembler.GetInstructionAt(0x140002CA0));
target.Instructions.Insert(6, dna.BinaryDisassembler.GetInstructionAt(0x140002CA5));
target.Instructions.Insert(7, dna.BinaryDisassembler.GetInstructionAt(0x140002CAA));
target.Instructions.Insert(8, dna.BinaryDisassembler.GetInstructionAt(0x140002CAE));
target.Instructions.Insert(9, dna.BinaryDisassembler.GetInstructionAt(0x140002CB2));
target.Instructions.Insert(10, dna.BinaryDisassembler.GetInstructionAt(0x140002CB6));
target.Instructions.Insert(11, dna.BinaryDisassembler.GetInstructionAt(0x140019225));
target.Instructions.Insert(12, dna.BinaryDisassembler.GetInstructionAt(0x14001922A));
// Print the disassembled control flow graph.
var prompt = () =>
{
Console.WriteLine("Press enter to continue...");
//Console.ReadLine();
};
Console.WriteLine("Disassembled cfg:\n{0}", GraphFormatter.FormatGraph(cfg));
Console.WriteLine(GraphFormatter.FormatGraph(cfg));
prompt();
// Instantiate the cpu architecture.
var architecture = new X86CpuArchitecture(ArchitectureId.ARCH_X86_64);
// Instantiate a class for lifting control flow graphs to our intermediate language.
var cfgLifter = new CfgLifter(architecture);
// Lift the control flow graph to TTIR.
var liftedCfg = cfgLifter.LiftCfg(cfg);
for (int i = 0; i < 3; i++)
Console.WriteLine("");
// Elminate deadcode from the control flow graph.
bool dce = false;
if (dce)
{
var blockDcePass = new BlockDcePass(liftedCfg);
blockDcePass.Run();
}
// Print the optimized control flow graph.
Console.WriteLine("Lifted cfg:\n{0}", GraphFormatter.FormatGraph(liftedCfg));
prompt();
// Create a .DOT file for visualizing the IR cfg.
var dotGraph = GraphVisualizer.GetDotGraph(liftedCfg);
File.WriteAllText("graph.dot", dotGraph.Compile(false, false));
bool emulate = false;
if(emulate)
{
// Load the binary into unicorn engine.
var emulator = new UnicornEmulator(architecture);
//PEMapper.MapBinary(emulator, binary);
ulong tebBase = 0x7fded000;
ulong tebSize = 0x10000;
emulator.MapMemory(tebBase, (int)tebSize);
//emulator.MapMemory(0, (int)tebSize);
//var igt = new GdtHelper(emulator.Emulator, 0x0, 0x1000);
//igt.Setup(tebBase);
// Setup the stack.
ulong rsp = 0x100000000;
emulator.MapMemory(rsp, 0x1000 * 1200);
rsp += 0x20000;
ulong pebAddr = 0x9A67F99120;
emulator.MapMemory(pebAddr - 0x120, 0x1000);
UInt16 val = 0x4A63;
emulator.WriteMemory(pebAddr, BitConverter.GetBytes(val));
int theSize = 0x1000 * 10;
emulator.MapMemory(0, theSize);
for(int i = 0; i < theSize; i++)
{
// emulator.WriteMemory((ulong)i, new byte[] { 0xFF });
}
//ulong gs = 0x1000;
//emulator.MapMemory(0, 0x1000 * 1000);
//emulator.SetRegister(register_e.ID_REG_X86_GS, 0);
//emulator.SetRegister(register_e.ID_REG_X86_FS, 0);
emulator.SetRegister(register_e.ID_REG_X86_RSP, rsp);
emulator.SetRegister(register_e.ID_REG_X86_RBP, rsp);
//emulator.SetRegister(register_e.ID_REG_X86_RIP, 0x14000177E);
// Execute the function.
emulator.Start(0x14000177E);
}
Console.WriteLine("Started");
// Lift the control flow graph to LLVM IR.
var llvmLifter = new LLVMLifter(architecture);
llvmLifter.Lift(liftedCfg);
llvmLifter.Module.PrintToFile(@"lifted.ll");
bool optimize = true;
if (optimize)
{
var passManager = llvmLifter.Module.CreateFunctionPassManager();
passManager.AddBasicAliasAnalysisPass();
passManager.AddTypeBasedAliasAnalysisPass();
passManager.AddScopedNoAliasAAPass();
passManager.AddLowerExpectIntrinsicPass();
passManager.AddCFGSimplificationPass();
passManager.AddPromoteMemoryToRegisterPass();
passManager.AddEarlyCSEPass();
passManager.AddDCEPass();
passManager.AddAggressiveDCEPass();
passManager.AddDeadStoreEliminationPass();
passManager.AddInstructionCombiningPass();
passManager.AddCFGSimplificationPass();
passManager.AddDeadStoreEliminationPass();
passManager.AddAggressiveDCEPass();
passManager.InitializeFunctionPassManager();
for (int i = 0; i < 10; i++)
{
passManager.RunFunctionPassManager(llvmLifter.llvmFunction);
}
passManager.FinalizeFunctionPassManager();
}
// Optionally write the llvm IR to the console.
bool printLLVM = true;
if (printLLVM)
llvmLifter.Module.Dump();
prompt();
// Optionally decompile the lifted function to go-to free pseudo C, via Rellic.
// On my machine, a fork of Rellic runs under WSL2 and communiucates via gRPC.
// If you are not hosting this server at localhost:50051, then the API
// call will fail. You can find the service here(https://github.com/Colton1skees/rellic-api),
// although it will take a bit of leg work for outside use.
bool decompile = false;
if (decompile)
{
// Create a decompiler instance.
var decompiler = new Decompiler(architecture);
// Decompile the lifted function to pseudo C.
var ast = decompiler.Decompile(llvmLifter.Module);
// Print the decompiled routine.
Console.WriteLine("Decompiled routine:\n{0}", ast);
}
Console.WriteLine("Finished.");
Console.ReadLine();