NCTF RE
16bit
16進制的匯編閱讀訓練。匯編賊煩,還好師傅手下留情,邏輯段一點不復雜,拖進ida//ida牛逼,查看start函數,跟到sub_100ac下面,看的出來這個是主函數
mov di, 3
call sub_10115
mov di, 24h ; ‘$’
call sub_10123
mov bx, 24h ; ‘$’//輸入
add bx, 1
cmp byte ptr [bx], 23h ; ‘#’//不是35個字符gg
jnz short loc_100DD
之后跳轉這兒
mov di, 26h ; ‘&’
call sub_100F9
mov si, 76h ; ‘v’
mov dx, 23h ; ‘#’
call sub_100E4//這個是對比,對比輸入的跟偏移值位76h的地方的是否相等,相等ok
test ax, ax
jnz short loc_100DD
其中sub_100f9是解釋器
進去loc_100FE:
mov al, [bx+si]
mov dl, al
mov cl, 3
shr al, cl//input[i]>>3
mov cl, 5
shl dl, cl//input[i]<<5
xor al, dl//之后抑或操作下
mov [bx+si], al
inc si
cmp si, 23h ; ‘#’
jnz short loc_100FE
之后很明顯了,逆向的話就是將原本存在內存中用來對比的//就是加密好的那個先右移3位,再左移5位,之后抑或,貼逆向代碼
#include<stdio.h>
int main(){
2.后門
大水題,找函數,按r,注意xx=0,x0=x,之后就是個換位操作,結束。
3.box
王師傅的box,一開始沒做出來的,因為找不到那個數組中的20,后來跟隊友閑扯發現有段函數不能偽c,懷疑有貓膩,于是讀匯編,貼匯編:
sub_400EB9 proc near ; DATA XREF:.init_array:0000000000601E10↓o
.text:0000000000400EB9
.text:0000000000400EB9 var_4 = dword ptr -4
.text:0000000000400EB9
.text:0000000000400EB9 ; __unwind {
.text:0000000000400EB9 push rbp
.text:0000000000400EBA mov rbp, rsp
.text:0000000000400EBD mov [rbp+var_4], 0
.text:0000000000400EC4 jmp short loc_400EE6
.text:0000000000400EC6 ;---------------------------------------------------------------------------
.text:0000000000400EC6
.text:0000000000400EC6 loc_400EC6: ; CODE XREF:sub_400EB9+34↓j
.text:0000000000400EC6 mov eax, [rbp+var_4]
.text:0000000000400EC9 cdqe
.text:0000000000400ECB movzx edx, byte_6020A0[rax]
.text:0000000000400ED2 mov eax, [rbp+var_4]
.text:0000000000400ED5 xor edx, eax
.text:0000000000400ED7 mov eax, [rbp+var_4]
.text:0000000000400EDA cdqe
.text:0000000000400EDC mov byte_6020A0[rax], dl
.text:0000000000400EE2 add [rbp+var_4], 1
.text:0000000000400EE6
.text:0000000000400EE6 loc_400EE6: ; CODE XREF:sub_400EB9+B↑j
.text:0000000000400EE6 cmp [rbp+var_4], 191
.text:0000000000400EED jle short loc_400EC6
.text:0000000000400EEF push rax
.text:0000000000400EF0 xor rax, rax
.text:0000000000400EF3 jz short loc_400EF9
.text:0000000000400EF5 add rsp, 40
.text:0000000000400EF9
.text:0000000000400EF9 loc_400EF9: ; CODE XREF:sub_400EB9+3A↑j
.text:0000000000400EF9 pop rax
.text:0000000000400EFA nop
.text:0000000000400EFB pop rbp
.text:0000000000400EFC retn
讀了下,發現是對那個后來比較的那個數組進行加密,加密方法是a[i]=a[i]^I;
之后加密完得到地圖:
//為了好看我把20改成2了,這樣對齊
//a,b,c是三個特殊的起始點,后面會寫
之后看主函數,最上面是那個神奇(可惡)的兔子函數,里面會有個sub_400796(),點進去發現是個初始化點坐標//就是我標出的a,b,c三點的初始坐標
之后,在主函數里面會有四個函數,分別對應4,5,W,0的情況,鑒于差不多,我就只發4的情況的那個函數的解析://那些變量被我用n健換成了a,b,i,j,n,m,看著舒服
_int64 sub_400C62()
{
__int64 result; // rax
result = (unsigned __int8)byte_6020A0[16 * i - 1 + j];
if( (_BYTE)result != 8 )
if ( j - 1 != m || i != n )
{if ( j - 1 == a && i == b ){if ( byte_6020A0[16 * b - 1 + a] == 8 )++j; elsesub_400A1C(&a); }else if ( byte_6020A0[16 * n - 1 + m] == 8 )
{++j; }else
{sub_400A1C(&m); }result= (unsigned int)(j-- - 1);}
return result;
}
之后三個類似,最后得出4左,5下,W上,0右
這個是個推箱子游戲
玩吧,之后把操作情況交上去就可以出flag了
4.基本操作:
直接看main
puts(“Input flag:”);
__isoc99_scanf("%64s", input); // 輸入的是個樹
i =0;
sub_400666(0); // 樹的前序遍歷
if(!strcmp(&s1, “bcec8d7dcda25d91ed3e0b720cbb6cf202b09fedbc3e017774273ef5d5581794”))
{
memset(&s1, 0, 0x80uLL);
i= 0;sub_4006BE(0, 0LL); // 樹的中序遍歷
if ( !strcmp(&s1,“7d8dcdcaed592e1dcb07e02c36bcb2f0bf9e0bdcb0e13777237e25fd48515974”) )
printf("TQL! TQL! flag: nctf{%s}\n", input);else
puts("Emmmm.....");result = 0LL;
}
else
{
puts(“GG!”);
result = 0LL;
}
return result;
}
然后就很清楚了,這個是個給了你二叉樹前序遍歷下來后的字符串跟中序遍歷的字符串
之后注意一個這個輸入的是個字符串,所以畫下來是個標準二叉樹,標準的!!!所以每個節點都是有左右子樹的!,64個字符,就是6層帶最后還有一個連著,之后開始就很舒服了,就根據前序遍歷的規則挨個寫//其實這個是a掉后看著樹才想到的,一開始做的時候,感謝我們隊的密碼手幫我手算出來。//都快算哭了,特別是知道可以這么玩后。
所以可以寫個程序,輸出64之內的標準二叉樹前序遍歷之后的輸出順序,之后跟題目中的對照,再得到flag。
貼代碼
#include
using namespace std;
void pro(int i)
{
if(i<=63){cout<<i<<"";pro(2*i+1);pro(2*i+2);}
else
return;
}
int main()
{
pro(0);}
得到輸出順序,對比得flag
還有題wcyvm,不知道為什么指令集好像搞崩掉了,先鴿著。
Ceypto
Math of homura
放到vscode中看源碼,先貼源碼
import gmpy2
import random
import GetFlag
c =random.randint(2 ** 127,2**128)
c = gmpy2.mpfr?
print “Homura sent some message afterdisappearing.”
print “But it was encoded and no onecan understand it.”
print “Fortunately you findsomething:”
print c
print “May be it will be useful.”
flag = GetFlag.getFlag()
mess = GetFlag.message()
i = 1
print “Here is the encodedmessage”
for ch in mess:
b=random.randint(2 ** 127,2**128)b= gmpy2.mpfr(b)a= gmpy2.root(b*b+c*c,2)x= gmpy2.mpfr((gmpy2.mpfr(ord(ch))/128.0)*(a))y= gmpy2.root((b*b-((b*b)/(a*a))*(x*x)),2)l1= gmpy2.root((((x+c)**2)+(y**2)),2)l2= gmpy2.root((((x-c)**2)+(y**2)),2)print"l1[%d]:"%iprintl1print"l2[%d]:"%iprintl2i+=1print “Now tell me what homurasaid?”
ans = raw_input()
if ans == mess:
printflagelse:
print"No you did not understand what homura said."然后數學計算嘛,算下來是
L1=a+ch*c/128
L2=a-ch*c/128
之后l1-l2就是ch*c/64,c是給出了的
然后將它輸出的東西進行操作,得到ascll碼表,不過注意的是它這個居然是變化的!!!一開始以為是靜態不變的直接用上次得到的數據逆向結果答案錯了,所以要用pwn的思路。。。
之后還有個坑就是,它算下來不是精確的整數,會有微小偏差,如果直接變成字符會報錯,所以還要+0.5后去除小數,貼代碼
from pwn import *
r = remote(‘ctfgame.acdxvfsvd.net’, 30002)
r.recvuntil(‘Your Token:\n’)
r.sendline(‘a8x69OokWdZJrRAyfCzhKFSiu6tlS8bg’)
r.recvuntil(‘something:\n’)
c=r.recvline()
payload =’’
r.recvuntil(‘message\n’)
for i in range(261):
a = r.recvline(keepends=True)
l1 = r.recvline(keepends=True)
a = r.recvline(keepends=True)
l2 = r.recvline(keepends=True)
k=float(l1)-float(l2)
k=k/float?*64+0.5
r.recvuntil(‘said?\n’)
r.sendline(payload)
r.interactive()
EAX:累加(Accumulator)寄存器,常用于函數返回值
EBX:基址(Base)寄存器,以它為基址訪問內存
ECX:計數器(Counter)寄存器,常用作字符串和循環操作中的計數器
EDX:數據(Data)寄存器,常用于乘除法和I/O指針
ESI:源變址寄存器
DSI:目的變址寄存器
ESP:堆棧(Stack)指針寄存器,指向堆棧頂部
EBP:基址指針寄存器,指向當前堆棧底部
EIP:指令寄存器,指向下一條指令的地址
call指令隱含操作push EIP,ret指令隱含操作 pop EIP
總結
- 上一篇: bzoj 3620: 似乎在梦中见过的样
- 下一篇: 用网盘(dropbox,kuaipan,