強網先鋒

base64

justre

  • windows逆向,打開main後,定位字元串到達sub_401BD0函數
  • 內部如下
  • 其中輸入存在v1中,傳入兩個函數,一個是1610,一個是18a0,其中18a0裡面什麼也沒有但是查看彙編可以看到大段明顯的位元組數據,懷疑這裡存在smc(代碼自修改)或者花指令,而下圖中的CODE XREF更證明了我的猜測,也就是說sub_401610函數中存在對這段代碼進行修改的過程

  • 逆向sub_401610函數發現前面是很熟悉的字元串轉data,也就是類似於"1"->1的轉換操作後面就是一堆很煩人的SSE指令集

但是可以看一下參數,這些東西和輸入沒有什麼關係,這裡先不管,那麼輸入其實是到了下一行的地方

這裡的v20是循環下標i,v3和v11都是之前輸入轉換成的數據,這裡用來運算,循環8輪,這裡實際上就是8個算式,這裡用z3解出來結果

from z3 import *

S = Solver()
x = BitVec("x",32)
y = BitVec("y",32)

S.add(y == y&0xff)

data = [ 659593944,
663789525,
51647302,
207884977,
4277163693,
52128309,
2387884190,
22803995]

enc = [ 608471104,
612666700,
508,
256901226,
472138769,
1005800,
2369808896,
38282372]

for i in range(16,24):
S.add(enc[i-16] == (i + x) ^ (0x1010101 * y + data[i-16]))

print S.check()
print S.model()

這裡拿到的是前十位的結果,之前的逆向可知,輸入格式是hex。

偽代碼中出現了rdtsc,是獲取時間的操作,這裡利用這個來實現反調試,當調試的時候,運行處在兩個rdtsc彙編指令中間的代碼就會花費更長的時間。通過這個時間差便可以檢測是否處在調試中

後面直接是明文比較,所以其實可以直接將數據從401848中拿出來複制到18a0的函數頭的位置,恢復後面的函數可以發現,很明顯的des,而且調用了三次,這裡直接將key dump下來,便可以獲取後段flag

wasm

又是wasm逆向,這種題目說白了其實都是各種套路,當時手慢了只拿了一個三血

這種題目其實就是wasm2c,然後配合著wasm2c中存在的幾個頭文件,進行編譯,注意不要鏈接,會報錯,其實就是藉助gcc優化一下wasm2c的c語言代碼,有興趣的可以看看那個c有多麼難看。。

但是配合gcc的優化,就變得好了很多,可以很明顯的看出來是個xtea了

一共4次xtea,key為0,後面連續xor驗證,所以提取出來然後進行decode就行了

這種題目其實是需要各種工具,文件一起逆向,後面函數的功能則需要利用瀏覽器進行調試,最後整理出演算法

固件逆向

給了一個鏡像,/bin/hello文件是要求逆向的東西,這裡將程序拿出來發現是一個mips架構的程序,ida簡單逆向可以看出來,兩個輸入,一個username一個password,然後進行驗證,先說逆向的演算法部分,username的驗證其實就是一個簡單的類似於明文比較的東西

這裡直接拿到username : 2cbca

然後進入400CC4驗證password,可以看一下流程圖

是一個類似於分發器的東西,裡面存在一些關鍵運算比如mul,位移,取值等等

在數據區域發現了兩個數組,一個是很明顯的flagenc,另一個是類似於opcode的位元組碼,位元組碼決定flag的運算,最後逐位和flagenc進行比較,注意這裡不是採用的單表加密

在jeb-mips中的偽代碼也可以看出一堆if else,應該是switch的另外一種表示,但是結構體什麼的都特別亂,反編譯出的偽代碼大概是下面的樣子

void* sub_4000CC4(void* param0){
unsigned int v0;
void* ptr0 = param0;
void* ptr1 = malloc(256);
unsigned int v1 = (unsigned int)&enc;
*ptr = 0;
param0 = ptr0 + 40;
unsigned int v2 = ptr1 + 96;
unsigned int v3 = ptr1 + 96;

do{
v0 = * v1;
v1 += 4;
*v2 = (short)(*param0);
++param0;
*v3 = v0;
v2 += 2;
v3 += 4;
}
while(v1 != 4264128);

*(ptrl + 8) = code;
*(ptr1 + 12) = what;
param0 = ptr1;
unsigned int v4 = *(ptr1 + 8);
v1 = 0;
loc_400850:

do{
ptr1 = v1*2;

while(1){
ptr1 = ((unsigned int)(((int)ptr1) + v1))*2 + v4;
v0 = (unsigned int)(*(ptr1 + 1));
++v1;
v3 = (unsigned int)(*ptr1);
v2 = (int)(*(ptr1+2));
ptr1 = (int)(*(ptr1 + 4));
*param0 = v1;

if(v0 == 0 || *(para + 4) == v0){
v0 = v3 < 10 ? 1:0;

if(v3 == 9){
printf("qwe");
return 0;
}
else if(v0 == 0){
v0 = v3<14?1:0;

if(v3 == 13){
v1 = *(para0 + 12);
v2 = v2 * 4 + v1;
*v2 = (unsigned int)(((int)(*(((unsigned int)(((int)ptr1)*4))+v1)))*((int)(*v2)));
v1 = *param0;
ptr1 = v1*2;
continue;
}
else if(v0 != 0){
unsigned char v5 = v3 == 11;
v3 = v3 < 12 ? 1 : 0;
v1 = *(param0 + 12);

if(!v5 && v3 == 0){
v2 = v2*4 + v1;
*v2 = *(((unsigned int)(((int)ptr1)*4))+v1)^*v2;
}
else if(!v5){
ptr1 = (void*)((*(((unsigned int)(((int)ptr1)*4))+v1)+8)*2 + ((int)param0));
*(v2*4 + v1) = (int)(*ptr1);
}
else{
*(v2*4 + v1) = *((unsigned int*)((*(((unsigned int)(((int)ptr1)*4))+v1)+24)*4 + ((int)param0)));
}

v1 = *param0;
ptr1 = v1*2;
continue;
}
else{
v0 = v3 < 15 ? 1 : 0;

if(v3 == 15){
v1 = *(para0 + 12);
v2 =v2*4+ v1;
*v2 = *v2 < ((unsigned int)(unsigned char)(*((unsigned int)(((int)ptr1) * 4)) + v1))));
ptr1 = v1 * 2;
continue;
}
else if(v0 != 0) {
v1 = *(param0 + 12);
v2=v2*4+v1;
v1 = *(((unsigned int)(int)ptr1) * 4)) + v1);
unsigned int v6 = (unsigned int)(((int)(*v2)) / ((int)v1));

if(v1 == 0){
_asm(" BREAK 7");
}
*v2 = v6;
v1 = *parame;
ptr1=v1*2;
continue;
}
else{
ptr1 = (void*)(((int)ptr1) * 4);

if(v3 == 16){
v1 = *(parame + 12);
v2 =v2*4+ v1;
*v2 = *v2 >> ((unsigned int)(unsigned char)(*((unsigned int*)(((int)ptr1) + v1)))));
v1 = *param0 ;
ptr1 =v1 * 2;
continue;
}
else if(v3 != 255){
goto loc_ 400850;
}
else {
return 1;
}
}
}
}
else{
v0=v3<5?1:0;

if(v3 == 4){
v1 += v2;
*param0 = v1;
goto loc_ 400850;
}
else if(v0 != 0){
v0=v3<3?1:0;

if(v3!=2&&v0==0){
v3 = *(param0 + 12);
*(param0 + 4) = *(((unsigned int)(((int)ptr1) * 4)) + v3) != *(v2*4+ v3) ? 2: 1;
goto loc_ 400850;
}
else if(v3 != 2){
ptr1 = (void*)(((int)ptr1) * 4);
if(v3 != 1){
goto loc_ 400850;
}
else{
v1 = *(param0 + 12);
v2=v2*4 + v1;
*v2 = *((unsigned int*)(((int)ptr1) + v1)) + *v2;
v1 = *param0;
ptr1=v1*2;
continue;
}
}
else{
v1 = *(param0 + 12);
v2=v2* 4 + v1;
*v2 = *v2 - *(((unsigned int)(((int)ptr1) * 4)) + v1);
v1 =*param0;
ptr1=v1*2;
continue;
}
}
else{
v0=v3<б?1:0;

if(v3 == 6){
*(v2 * 4 + *(param0 + 12)) = (int)(((unsigned short)v1));
v1 = *param0;
ptr1=v1*2;
continue;
}
else if(v0 != 0){
v1 = *(param0 + 12);
*(v2 * 4 + v1) = *(((unsigned int)((int)ptr1) * 4)) + v1);
v1 = *param0;
ptr1 = v1 * 2;
continue;
}
else if(v3 != 7){
v2 *= 4;

if(v3 != 8){
goto loc_400850;
}
else{
*(*(param0 + 12) + v2) = ptr1;
v1 = *param0;
ptr1 = v1*2;
continue;
}
}
}
}
v1 = *(v2*4 + *(param0 + 12));
*param0 = *(v2 * 4 + *(param0 + 12));
}

goto loc_400850;
}
}
while(1);
return 1;

}

最後了解了一下大概邏輯,配合著調試和彙編,整理演算法,發現在乘法的代碼塊中,幾個寄存器會出現輸入,最後整理出演算法為input[i] = (input[i] * out) >> 6,其中out的初值為0x1024,out += i,爆破flag

s = "5B0C0000DD0C00001F0D0000C0180000C6180000260C0000720E0000F70D0000B1190000410D0000080D00001C190000D90C0000B10E0000EE0C0000781A00008B0D0000990D0000640D0000ED0C0000F8190000610E00007F1A0000E71A0000260F0000341B0000D01A00007C0D0000C90F00007E0E00000E1C0000AE1B0000".decode("hex")

from pwn import *

flagenc = []

for i in range(0,len(s),4):
flagenc.append(u32(s[i:i+4]))

flag = ""

out = 0x1024

for i in range(len(flagenc)):
for j in range(33,127):
if(((j * out) >> 6) == flagenc[i]):
flag += chr(j)
print flag
out += (i + 1)

print flag

安卓

這個題還沒有調試環境,過幾天再補上吧

  • 靜態逆了一下,拿到aes,懷疑ollvm了aes,然後還能拿到32位元組懷疑是key,memcmp拿到80位元組的待比較數據,題目中存在5次aes的過程

有不對的還要請師傅們多多指正。。。


推薦閱讀:
相关文章