新人第一次尝试CM,欢迎尝试
本帖最后由 wtdcode 于 2021-12-6 07:54 编辑正确的话会输出 You are the real pro!
错误的话会输出 Try harder!
没有壳,没有花指令,不要被反汇编吓到了,提示:Unicorn Engine
预期解包括逆向算法和爆破,两种做法都很有意思,可以都尝试一下。期待有人能给出算法 {:1_905:} __int64 sub_401783()
{
__int64 input; // BYREF
int INPUT; // BYREF
char v3; // BYREF
__int64 uc; // BYREF
unsigned __int64 i; //
sub_142DED0();
if ( uc_open(8i64, 4i64, &uc) )
abort();
if ( uc_mem_map(uc, 0x6000i64, 0x3000i64, 7i64) )
abort();
if ( uc_mem_write(uc, 0x7000i64, &unk_1437010, 29i64) )
abort();
if ( uc_mem_write(uc, 0x8000i64, &unk_1437030, 28i64) )
abort();
if ( uc_setHook(uc, v3, 4i64, sub_401550, &input, 1i64, 0i64) )
abort();
for ( i = 0i64; i <= 0x1B; ++i )
{
input = getchar();
if ( i == 27 )
{
if ( input != 10 )
{
put("Try harder!\n");
exit(0);
}
break;
}
input |= i << 32;
INPUT = input;
if ( uc_reg_write(uc, 2, &INPUT) ) // al=input
//
abort();
INPUT = 0;
if ( uc_reg_write(uc, 3, &INPUT) )
abort();
if ( uc_reg_write(uc, 4, &INPUT) )
abort();
if ( uc_start(uc, 0x7000i64, 0x701Ci64, 0i64, 0i64) )
abort();
if ( uc_reg_read(uc, 2i64, &INPUT) ) // 获取al
abort();
if ( INPUT )
{
put("Try harder!\n");
exit(0);
}
}
put("You are the real pro!\n");
if ( uc_close(uc) )
abort();
return 0i64;
}
unsigned __int64 __fastcall sub_401550(__int64 a1, __int64 a2, __int64 a3, __int64 *a4)
{
unsigned __int64 result; // rax
int v5; // eax
int v6; // BYREF
int v7; // BYREF
int v8; // BYREF
int v10; //
int v11; //
int v13; //
unsigned __int64 v14; //
__int64 v15; //
unsigned __int64 v16; //
v16 = *a4;
v15 = v16;
v14 = HIDWORD(v16);
v6 = HIDWORD(v16) + 0x8000;
result = uc_reg_write(a1, 3, &v6);
v13 = result;
if ( result )
abort();
if ( a2 == 0x7004 )
{
if ( v14 % 5 <= 3 )
{
result = v14 % 5;
if ( v14 % 5 <= 2 )
{
v8 = 28680;
result = uc_reg_write(a1, 190, v8);
v10 = result;
if ( result )
abort();
}
}
else
{
v5 = v15;
LOBYTE(v5) = v15 ^ 0x9E;
v8 = v5;
v7 = 28684;
if ( uc_reg_write(a1, 2, v8) )
abort();
result = uc_reg_write(a1, 190, &v7);
v8 = result;
if ( result )
abort();
}
}
else if ( a2 == 0x7008 )
{
if ( v14 % 5 == 1 || (result = v14 % 5, v14 % 5 == 3) )
{
if ( uc_reg_read(a1, 2i64, v8) )
abort();
v8 = (LOBYTE(v8) + 7);
result = uc_reg_write(a1, 2, v8);
v11 = result;
if ( result )
abort();
}
}
return result;
}
没时间搞了,给后来者一点提示吧,该标注的都标注了 考虑已经有人解出来了,所以直接公布代码
#include "unicorn/unicorn.h"
#include <cstdint>
#include <cstdio>
uint8_t code[] = "\x93\xc0\x50\x04\x93\xc0\x90\x08\x93\xc0\x20\x00\x83\x01\x01\x00\x93\xf1\xf1\x0f\x93\xc1\x41\x07\xb3\x80\x30\x40";
uint8_t target[] = "\x44\x4e\x57\xc0\x85\x57\x51\x48\xb6\xa4\x5a\x5b\x5c\xd3\x84\x6c\x46\x7a\xd8\x8f\x6c\x5d\x6c\xd5\x98\x5c\x49";
// xori x1, x1, 0x45 0
// xori x1, x1, 0x89 4
// xori x1, x1, 0x28
// lb x3, 0(x2) c
// andi x3, x3, 0xff 10
// xori x3, x3, 0x74 14
// sub x1, x1, x3 18
#define OK(x) do { uc_err err = x; if (err) { std::abort(); }} while(0)
void hook_addr(uc_engine* uc, uint64_t addr, size_t sz, void* data) {
uint64_t combined = *((uint64_t*)data);
uint32_t val, pc;
uint64_t input = combined & (0xFFFFFFFF);
uint64_t round = (combined & (0xFFFFFFFF00000000UL) ) >> 32;
uint32_t x2 = round + 0x8000;
OK(uc_reg_write(uc, UC_RISCV_REG_X2, &x2));
if (addr == 0x7000 + 4) {
if ( round % 5 >= 4) {
val = input ^ 158;
pc = addr + 2 * 4;
//printf("input=%hx val!\n", input);
OK(uc_reg_write(uc, UC_RISCV_REG_X1, &val));
OK(uc_reg_write(uc, UC_RISCV_REG_PC, &pc));
} else if (round % 5 <= 2) {
val = addr + 4;
//printf("input=%hx redo!\n", input);
OK(uc_reg_write(uc, UC_RISCV_REG_PC, &val));
}
} else if (addr == 0x7000 + 8) {
if (round % 5 == 1 || round % 5 == 3) {
OK(uc_reg_read(uc, UC_RISCV_REG_X1, &val));
//printf("input=%hx x1=%hx mod!\n", input, val);
val = (val + 7) % 256;
OK(uc_reg_write(uc, UC_RISCV_REG_X1, &val));
}
}
}
int main() {
uc_engine* uc;
uc_hook hk;
uint32_t x1;
uint64_t input;
OK(uc_open(UC_ARCH_RISCV, UC_MODE_32, &uc));
OK(uc_mem_map(uc, 0x6000, 0x3000, UC_PROT_ALL));
OK(uc_mem_write(uc, 0x7000, code, sizeof(code)));
OK(uc_mem_write(uc, 0x8000, target, sizeof(target)));
OK(uc_hook_add(uc, &hk, UC_HOOK_CODE, (void*)hook_addr, (void*)&input, 1, 0));
for (uint64_t i = 0; i < 27 + 1; i ++) {
input = getchar();
if (i == 27) {
if (input != (uint64_t)'\n') {
printf("Try harder!\n");
std::exit(0);
} else{
break;
}
}
input |= (i << 32);
x1 = input;
OK(uc_reg_write(uc, UC_RISCV_REG_X1, &x1));
x1 = 0;
OK(uc_reg_write(uc, UC_RISCV_REG_X2, &x1));
OK(uc_reg_write(uc, UC_RISCV_REG_X3, &x1));
OK(uc_emu_start(uc, 0x7000, 0x7000 + sizeof(code) - 1, 0, 0));
OK(uc_reg_read(uc, UC_RISCV_REG_X1, &x1));
if (x1 != 0) {
printf("Try harder!\n");
std::exit(0);
}
}
printf("You are the real pro!\n");
OK(uc_close(uc));
} 本帖最后由 weikun444 于 2021-12-7 06:56 编辑
无奈,不懂算法,感兴趣的可以跟跟1783 weikun444 发表于 2021-12-6 17:57
无奈,不懂算法,爆的话,1783下断,18A3改NOP,18AD改JMP即可!
我说的爆破指的是通过枚举的方法得到正确的key{:1_918:}
不过在现实的攻防里这也是一种办法哈哈 #include <stdio.h>
#include <string.h>
unsigned char data[] = {68, 78, 87, 192, 133, 87, 81, 72, 182, 164, 90, 91, 92, 211, 132, 108, 70, 122, 216, 143, 108, 93, 108, 213, 152, 92, 73, 0};
/*
00007000 xori ar, ar, 0x45
00007004 xori ar, ar, 0x89
00007008 xori ar, ar, 0x2
0000700c lb gp, 0x0 =>Stack (sp)
00007010 andi gp, gp, 0xff
00007014 xori gp, gp, 0x74
00007018 sub ar, ar, gp
/**/
unsigned int check_elem(char value_in, int index) {
unsigned char value = value_in;
label_7004:
if (index % 5 == 4) {
value ^= 0x9E;
goto label_700C;
} else {
value ^= 0x45;
if (index % 5 != 3) goto label_7008;
}
value ^= 0x89;
label_7008:
if (index % 5 == 1 || index % 5 == 3) {
value += 7;
}
value ^= 0x2;
label_700C:
return value - (data ^ 0x74);
}
void reverse() {
char input;
input = 0;
for (int i = 0; i < 27; i++) {
unsigned char value = data ^ 0x74;
if (i % 5 == 4) {
value ^= 0x9E;
} else {
value ^= 0x2;
if (i % 5 == 1 || i % 5 == 3) {
value -= 7;
}
if (i % 5 == 3) value ^= 0x89;
value ^= 0x45;
}
input = value;
}
puts(input);
}
int check(char* input) {
if (strlen(input) != 27 && (strlen(input) != 28 || input != '\n')) return 0;
for (int i = 0; i < 27; i++) {
if (check_elem(input, i) != 0) return 0;
}
return 1;
}
int main() {
/*
if (check("wtdcode{uNicoRn_lIke_a_Pro}")) {
puts("OK.");
} else {
puts("NOP.");
}
/**/
reverse();
return 0;
}
Ichild 发表于 2021-12-7 15:29
#include
#include
正解 非常干净漂亮。 搜索曾经的回忆 发表于 2021-12-7 15:18
__int64 sub_401783()
{
__int64 input; // BYREF
{:1_918:}很接近了 wtdcode 发表于 2021-12-7 16:41
很接近了
模拟的是x86的汇编指令集吗?还是? 搜索曾经的回忆 发表于 2021-12-7 18:47
模拟的是x86的汇编指令集吗?还是?
RISC-V 上面正解里已经给出反汇编了 wtdcode 发表于 2021-12-7 18:49
RISC-V 上面正解里已经给出反汇编了
额,查unicorn官方文档,没查到这个指令集
页:
[1]
2