啊,做了一天牢,师傅们都出了,就我只能等wp😭
文件类型
64位elf文件
反编译
很奇怪,看不到主加密函数,只能跟到flag{…6813}就断了,后面的代码完全看不懂了,看wp所使用到了栈回溯,中间有地方抛出了异常,在回溯过程中用到了Dwarf expression对寄存器进行了更改也就是R12寄存器
xor r13 r13
cmp r12 r13
只有当r12为0时才会跳入yes模块
在此之前,由于x64没有采用传统的方法记录堆栈信息,而是通过.eh_frame段保存了栈寄存器等信息,我们需要读取这个段的信息进行还原栈回溯时对R12的操作
读取段信息
readelf -Wwf ezbyte >a.txt #W表示每行以特定字符输出,wf按CFA语法输出.eh_frame内容
- FDE代表某个函数的记录
- CIE代表一个文件,CIE下有多个FDE
- PS函数的起点和终点
分析函数,加密验证区域出现在flag{…381}这个地方
也就是这里不过我们直接利用rust字节码脚本还原用不到这个,本来用的python的方法,结果没找到解析器源码
rust和Cargo安装
curl --proto ‘=https’ --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env #应用环境变量
rustc --version #验证
sudo apt install cargo
给cargo换源:
vi ~/.cargo/config
[source.crates-io] registry = "https://github.com/rust-lang/crates.io-index" replace-with = 'ustc' [source.ustc] registry = "git://mirrors.ustc.edu.cn/crates.io-index"
安装完成
反编译
建立Cargo.toml文件与解析器analysis.rs
[package]
name = "analysis"
version = "0.1.0"
edition = "2021"
[dependencies]
gimli = "0.26.1"
object = "0.29.0"
[[bin]]
name = "analysis"
path = "analysis.rs"
// [dependencies]
// gimli = "0.26.1"
// object = "0.29.0"
use std::{collections::HashMap, fs, fmt::Display, io::Write};
use std::process::Command;
use gimli::UnwindSection;
use object::{Object, ObjectSection};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut arg = std::env::args();
if arg.len() != 2 {
panic!("Argument Error!")
}
let bin_data = fs::read(arg.nth(1).unwrap())?;
let obj_file = object::File::parse(&*bin_data)?;
let data = obj_file.section_by_name(".eh_frame").unwrap();
let eh_frame = gimli::read::EhFrame::new(data.data()?, gimli::LittleEndian);
let bases = gimli::BaseAddresses::default().set_eh_frame(data.address());
let mut entries = eh_frame.entries(&bases);
let mut file = fs::OpenOptions::new().append(false).truncate(true).write(true).create(true).open("./output.c")?;
writeln!(file, "#include <stdint.h>")?;
let mut cies = HashMap::new();
while let Some(entry) = entries.next()? {
if let gimli::CieOrFde::Fde(partial) = entry {
let fde = partial.parse(|_, bases, o| {
cies.entry(o)
.or_insert_with(|| eh_frame.cie_from_offset(bases, o))
.clone()
})?;
// 通过长度过滤出我们想要的
if fde.entry_len() < 100 {
continue;
}
let mut instructions = fde.instructions(&eh_frame, &bases);
use gimli::CallFrameInstruction::*;
loop {
match instructions.next() {
Err(e) => {
println!("Failed to decode CFI instruction: {}", e);
break;
}
Ok(Some(ValExpression {
register,
expression,
})) => {
println!(
"DW_CFA_val_expression ({}, ...)",
gimli::X86_64::register_name(register).unwrap_or("{unknown}")
);
display_val_expression(register, expression, &mut file)?;
}
Ok(None) => {
break;
}
_ => {}
}
}
}
}
file.flush()?;
Command::new("gcc")
.arg("-O3")
.arg("./output.c")
.arg("-c")
.spawn()?;
Ok(())
}
#[derive(Clone, Copy)]
struct Val {
id: u64,
}
impl Val {
fn new(id: u64) -> Self {
Val { id }
}
}
struct ValGenerator {
id: u64,
}
impl ValGenerator {
fn new() -> Self {
Self { id: 0 }
}
fn next(&mut self) -> Val {
self.id += 1;
Val::new(self.id - 1)
}
}
impl Display for Val {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "v{}", self.id)
}
}
fn display_val_expression<R>(target_reg: gimli::Register, exp: gimli::Expression<R>, w: &mut dyn Write) -> Result<(), Box<dyn std::error::Error>>
where
R: gimli::Reader,
{
let mut val_generator = ValGenerator::new();
let mut ops = exp.operations(gimli::Encoding { address_size: 8, format: gimli::Format::Dwarf64, version: 5 });
let mut stack: Vec<Val> = Vec::new();
writeln!(w, "uint64_t cal_{}(uint64_t r12, uint64_t r13, uint64_t r14, uint64_t r15){{", gimli::X86_64::register_name(target_reg).unwrap())?;
writeln!(w, " uint64_t rax=0,rbx=0;")?;
loop {
if let Ok(Some(op)) = ops.next() {
match op {
gimli::Operation::Drop => {
stack.pop();
}
gimli::Operation::Pick { index } => {
let val1 = stack.get(stack.len() - 1 - index as usize).unwrap();
let new_val = val_generator.next();
writeln!(w, " uint64_t {}={};", new_val, val1)?;
stack.push(new_val);
}
gimli::Operation::Swap => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
stack.push(val1);
stack.push(val2);
}
gimli::Operation::Rot => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
let val3 = stack.pop().unwrap();
stack.push(val1);
stack.push(val3);
stack.push(val2);
}
gimli::Operation::And => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
let new_val = val_generator.next();
writeln!(w, " uint64_t {}={}&{};", new_val, val2, val1)?;
stack.push(new_val);
}
gimli::Operation::Minus => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
let new_val = val_generator.next();
writeln!(w, " uint64_t {}={}-{};", new_val, val2, val1)?;
stack.push(new_val);
}
gimli::Operation::Neg => {
let val = stack.get(stack.len() - 1).unwrap();
writeln!(w, " {}=-{};", val, val)?;
}
gimli::Operation::Not => {
let val = stack.get(stack.len() - 1).unwrap();
writeln!(w, " {}=~{};", val, val)?;
}
gimli::Operation::Or => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
let new_val = val_generator.next();
writeln!(w, " uint64_t {}={}|{};", new_val, val2, val1)?;
stack.push(new_val);
}
gimli::Operation::Plus => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
let new_val = val_generator.next();
writeln!(w, " uint64_t {}={}+{};", new_val, val2, val1)?;
stack.push(new_val);
}
gimli::Operation::PlusConstant { value } => {
let val = stack.get(stack.len() - 1).unwrap();
writeln!(w, " {}+={}ull;", val, value)?;
}
gimli::Operation::Shl => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
let new_val = val_generator.next();
writeln!(w, " uint64_t {}={}<<{};", new_val, val2, val1)?;
stack.push(new_val);
}
gimli::Operation::Shr => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
let new_val = val_generator.next();
writeln!(w, " uint64_t {}={}>>{};", new_val, val2, val1)?;
stack.push(new_val);
}
gimli::Operation::Shra => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
let new_val = val_generator.next();
writeln!(w, " uint64_t {}=(uint64_t)((int64_t){}>>(int64_t){});", new_val, val2, val1)?;
stack.push(new_val);
}
gimli::Operation::Xor => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
let new_val = val_generator.next();
writeln!(w, " uint64_t {}={}^{};", new_val, val2, val1)?;
stack.push(new_val);
}
gimli::Operation::Eq => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
let new_val = val_generator.next();
writeln!(w, " uint64_t {}= {}=={}?1:0;", new_val, val2, val1)?;
stack.push(new_val);
}
gimli::Operation::Ge => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
let new_val = val_generator.next();
writeln!(w, " uint64_t {}={}>={}?1:0;", new_val, val2, val1)?;
stack.push(new_val);
}
gimli::Operation::Gt => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
let new_val = val_generator.next();
writeln!(w, " uint64_t {}={}>{}?1:0;", new_val, val2, val1)?;
stack.push(new_val);
}
gimli::Operation::Le => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
let new_val = val_generator.next();
writeln!(w, " uint64_t {}={}<={}?1:0;", new_val, val2, val1)?;
stack.push(new_val);
}
gimli::Operation::Lt => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
let new_val = val_generator.next();
writeln!(w, " uint64_t {}={}<{}?1:0;", new_val, val2, val1)?;
stack.push(new_val);
}
gimli::Operation::Ne => {
let val1 = stack.pop().unwrap();
let val2 = stack.pop().unwrap();
let new_val = val_generator.next();
writeln!(w, " uint64_t {}={}!={}?1:0;", new_val, val2, val1)?;
stack.push(new_val);
}
gimli::Operation::UnsignedConstant { value } => {
let new_val = val_generator.next();
writeln!(w, " uint64_t {}={}ull;", new_val, value)?;
stack.push(new_val);
}
gimli::Operation::SignedConstant { value } => {
let new_val = val_generator.next();
writeln!(w, " uint64_t {}=(uint64_t){}ll;", new_val, value)?;
stack.push(new_val);
}
gimli::Operation::RegisterOffset { register, offset, base_type} => {
let new_val = val_generator.next();
writeln!(w, " uint64_t {}={};", new_val, gimli::X86_64::register_name(register).unwrap_or("{error}"))?;
stack.push(new_val);
}
_ => todo!("{:?}", op)
}
} else {
break;
}
}
assert_eq!(stack.len(), 1);
writeln!(w, " return {};", stack.pop().unwrap())?;
writeln!(w, "}}\n")?;
Ok(())
}
- cargo build
- cargo run – ./ezbyte_patch
可以得到以下文件,函数保留在output.o文件下
wp
#include"stdio.h"
//#define a1{a5,a2,a3,a4}
int main(){
long long a[4];
a[0] =0x35626665394D17E8LL -1892739;
a[1] =0x65342D6530C04912LL -8971237;
a[2] =0x2D393663614447B1LL -1512312;
a[3] =0x6336396431BE9AD9LL -9123704;
for(int i=0;i<4;i++){
for(int j=0;j<8;j++){
putchar((a[i]>>j*8)&0xff);
}
}
return 0;
}
//e609efb5-e70e-4e94-ac69-ac31d96c
__int64 __fastcall cal_r12(__int64 a1, __int64 a2, __int64 a3, __int64 a4)
{
return (a1 + 1892739) ^ 0x35626665394D17E8LL | (a2 + 8971237) ^ 0x65342D6530C04912LL | (a4 + 9123704) ^ 0x6336396431BE9AD9LL | (a3 + 1512312) ^ 0x2D393663614447B1LL;
}
flag{e609efb5-e70e-4e94-ac69-ac31d96c}
参考链接:
https://mdnice.com/writing/dae27f3c9b584d34b156fbf1a392ad85
https://blog.csdn.net/zhuliliang/article/details/114976890