[zctf 2016] reverse 100 write up

1. 首先跑跑程序,看看是个什么模式。发现输入了密码之后,啥都没有了,这样我们就不能从程序反馈找关键点了。从程序里面找找看。


2. 果然是第一道题,各种信息提示都有,好了,那么就可疑字符串进去看看吧。


3. 发现这个函数把这些话的空格去掉了,并且取前面的十六个字符。


4. 那么就看第一个函数。发现就是一个求解多元函数的解的方程组,直接用矩阵求解就好,这里还学习了一些用excel求解多元方程组。excel真是神奇。
具体如何用excel解方程组,百度一下就知道。
多元方程组的伪代码

int __cdecl main(int argc, const char **argv, const char **envp)
{
  signed int v3; // ebx@3
  int *v4; // ebp@3
  char *v5; // esi@3
  int v6; // edi@4
  signed int v7; // eax@4
  void *v8; // esi@8
  signed int v9; // edi@8
  int v10; // eax@8
  int v11; // ecx@11
  int v12; // eax@12
  int v14; // [sp+10h] [bp-690h]@3
  int v15; // [sp+14h] [bp-68Ch]@3
  int v16; // [sp+18h] [bp-688h]@3
  int v17; // [sp+1Ch] [bp-684h]@3
  int v18; // [sp+20h] [bp-680h]@3
  int v19; // [sp+24h] [bp-67Ch]@3
  int v20; // [sp+28h] [bp-678h]@3
  int v21; // [sp+2Ch] [bp-674h]@3
  int v22; // [sp+30h] [bp-670h]@3
  int v23; // [sp+34h] [bp-66Ch]@3
  int v24; // [sp+38h] [bp-668h]@3
  int v25; // [sp+3Ch] [bp-664h]@3
  int v26; // [sp+40h] [bp-660h]@3
  int v27; // [sp+44h] [bp-65Ch]@3
  int v28; // [sp+48h] [bp-658h]@3
  int v29; // [sp+4Ch] [bp-654h]@3
  char InputPassword[12]; // [sp+50h] [bp-650h]@1
  char v31; // [sp+60h] [bp-640h]@3
  char v32; // [sp+A3h] [bp-5FDh]@3
  char v33; // [sp+C3h] [bp-5DDh]@3
  char v34; // [sp+C4h] [bp-5DCh]@3
  __int16 v35; // [sp+DEh] [bp-5C2h]@3
  __int16 v36; // [sp+126h] [bp-57Ah]@3
  char v37; // [sp+128h] [bp-578h]@3
  __int16 v38; // [sp+162h] [bp-53Eh]@3
  __int16 v39; // [sp+18Ah] [bp-516h]@3
  char v40; // [sp+18Ch] [bp-514h]@3
  _BYTE v41[3]; // [sp+1C5h] [bp-4DBh]@3
  __int16 v42; // [sp+1EDh] [bp-4B3h]@3
  char v43; // [sp+1EFh] [bp-4B1h]@3
  char v44; // [sp+1F0h] [bp-4B0h]@3
  char v45; // [sp+22Bh] [bp-475h]@3
  char v46; // [sp+253h] [bp-44Dh]@3
  char v47; // [sp+254h] [bp-44Ch]@3
  int v48; // [sp+28Ch] [bp-414h]@3
  char v49; // [sp+2B8h] [bp-3E8h]@3
  int v50; // [sp+306h] [bp-39Ah]@3
  int v51; // [sp+30Ah] [bp-396h]@3
  int v52; // [sp+30Eh] [bp-392h]@3
  int v53; // [sp+312h] [bp-38Eh]@3
  int v54; // [sp+316h] [bp-38Ah]@3
  __int16 v55; // [sp+31Ah] [bp-386h]@3
  char v56; // [sp+31Ch] [bp-384h]@3
  int v57; // [sp+378h] [bp-328h]@3
  int v58; // [sp+37Ch] [bp-324h]@3
  char v59; // [sp+380h] [bp-320h]@3
  int v60; // [sp+3D1h] [bp-2CFh]@3
  int v61; // [sp+3D5h] [bp-2CBh]@3
  int v62; // [sp+3D9h] [bp-2C7h]@3
  int v63; // [sp+3DDh] [bp-2C3h]@3
  __int16 v64; // [sp+3E1h] [bp-2BFh]@3
  char v65; // [sp+3E3h] [bp-2BDh]@3
  char v66; // [sp+3E4h] [bp-2BCh]@3
  char v67; // [sp+40Bh] [bp-295h]@3
  char v68; // [sp+447h] [bp-259h]@3
  char v69; // [sp+448h] [bp-258h]@3
  __int16 v70; // [sp+482h] [bp-21Eh]@3
  __int16 v71; // [sp+4AAh] [bp-1F6h]@3
  char v72; // [sp+4ACh] [bp-1F4h]@3
  _BYTE v73[3]; // [sp+4EDh] [bp-1B3h]@3
  __int16 v74; // [sp+50Dh] [bp-193h]@3
  char v75; // [sp+50Fh] [bp-191h]@3
  char v76; // [sp+510h] [bp-190h]@3
  _BYTE v77[3]; // [sp+54Dh] [bp-153h]@3
  __int16 v78; // [sp+571h] [bp-12Fh]@3
  char v79; // [sp+573h] [bp-12Dh]@3
  char v80; // [sp+574h] [bp-12Ch]@3
  int v81; // [sp+5A8h] [bp-F8h]@3
  char v82; // [sp+5D8h] [bp-C8h]@3
  char v83; // [sp+623h] [bp-7Dh]@3
  char v84; // [sp+63Bh] [bp-65h]@3
  char v85; // [sp+63Ch] [bp-64h]@3
  _BYTE v86[3]; // [sp+67Dh] [bp-23h]@3
  __int16 v87; // [sp+69Dh] [bp-3h]@3
  char v88; // [sp+69Fh] [bp-1h]@3

  sub_401C00(&dword_4171C0, InputPassword);
  if ( strlen(InputPassword) != 16 )                #bigger than 16 chars 
    exit(0);
  qmemcpy(&v31, aMyDearForTheHu, 0x43u);
  memset(&v32, 0, 0x20u);
  v33 = 0;
  qmemcpy(&v34, aICannotChooseT, 0x1Au);
  memset(&v35, 0, 0x48u);
  v36 = 0;
  qmemcpy(&v37, aMyWishesAreFoo, 0x3Au);
  memset(&v38, 0, 0x28u);
  v39 = 0;
  qmemcpy(&v40, aWhatYouAreYouD, 0x39u);
  memset(v41, 0, 0x28u);
  v42 = 0;
  v43 = 0;
  qmemcpy(&v44, aDoNotSeatYourL, 0x3Bu);
  memset(&v45, 0, 0x28u);
  v46 = 0;
  qmemcpy(&v47, aDelusionsOfKno, 0x38u);
  memset(&v48, 0, 0x2Cu);
  qmemcpy(&v49, aListenMyHeartT, 0x4Eu);
  v50 = 0;
  v51 = 0;
  v52 = 0;
  v53 = 0;
  v54 = 0;
  v55 = 0;
  qmemcpy(&v56, aSomeUnseenFing, 0x5Cu);
  v57 = 0;
  v58 = 0;
  qmemcpy(&v59, aSorrowIsHushed, 0x51u);
  v60 = 0;
  v61 = 0;
  v62 = 0;
  v63 = 0;
  v64 = 0;
  v65 = 0;
  qmemcpy(&v66, aOnceWeDreamtTh, 0x27u);
  memset(&v67, 0, 0x3Cu);
  v68 = 0;
  qmemcpy(&v69, aHerWishfulFace, 0x3Au);
  memset(&v70, 0, 0x28u);
  v71 = 0;
  qmemcpy(&v72, aIfYouShedTears, 0x41u);
  memset(v73, 0, 0x20u);
  v74 = 0;
  v75 = 0;
  qmemcpy(&v76, aItIsTheTearsOf, 0x3Du);
  memset(v77, 0, 0x24u);
  v78 = 0;
  v79 = 0;
  qmemcpy(&v80, aThatIExistIsAP, 0x34u);
  memset(&v81, 0, 0x30u);
  qmemcpy(&v82, aGodExpectsAnsw, 0x4Bu);
  memset(&v83, 0, 0x18u);
  v84 = 0;
  qmemcpy(&v85, aOBeautyFindThy, 0x41u);
  memset(v86, 0, 0x20u);
  v87 = 0;
  v88 = 0;
  v14 = 179334;
  v15 = 175544;
  v16 = 180760;
  v17 = 182366;
  v18 = 182850;
  v19 = 180568;
  v20 = 181440;
  v21 = 178347;
  v22 = 181577;
  v23 = 176475;
  v24 = 174043;
  v25 = 179882;
  v26 = 178817;
  v27 = 175345;
  v28 = 178696;
  v29 = 175320;
  v3 = 0;
  v4 = &v14;
  v5 = &v31;<span style="white-space:pre">		</span><strong><span style="color:#ff0000;">#准备进行矩阵计算了---下面</span></strong>
  do
  {
    v6 = 0;
    sub_401000(v5);  <strong>#remove the space among the words</strong>
    v7 = 0;
    do
    {
      v6 += InputPassword[v7] * v5[v7];
      ++v7;
    }
    while ( v7 < 16 );
    if ( *v4 != v6 )
      exit(0);
    ++v3;
    v5 += 100; 
    ++v4;
  }
  while ( v3 < 16 );
  v8 = (void *)sub_402380(&unk_417130, aZctf_youAreAlm);
  sub_401820(v8, 0xAu);
  v9 = 0;
  v10 = (int)((char *)v8 + *(_DWORD *)(*(_DWORD *)v8 + 4));
  if ( !(*(_BYTE *)(v10 + 4) & 6)
    && (*(int (__thiscall **)(_DWORD))(**(_DWORD **)(v10 + 40) + 44))(*(_DWORD *)(v10 + 40)) == -1 )
    v9 = 4;
  v11 = (int)((char *)v8 + *(_DWORD *)(*(_DWORD *)v8 + 4));
  if ( v9 )
  {
    v12 = v9 | *(_DWORD *)(v11 + 4);
    if ( !*(_DWORD *)(v11 + 40) )
      LOBYTE(v12) = v12 | 4;
    std::ios_base::clear((std::ios_base *)v11, v12, 0);
  }
  return sub_401050(InputPassword);  <strong># check if you are really clever</strong>
}

用excel 求解,神奇的excel


根据这个方程组解出来的是flag"zctf{Wrong_Flag}". = =主办方真是爱开玩笑。


5. 再继续看,中间的处理看不是很懂,但是最后调用了一个函数“void __cdecl sub_401050(int inputPassword)”:
下面是伪代码。
void __cdecl sub_401050(int inputPassword)
{
  signed int v1; // eax@3
  signed int v2; // ecx@6
  int *v3; // esi@6
  int v4; // edx@7
  signed int i; // eax@7
  void *v6; // esi@11
  signed int v7; // edi@14
  int v8; // eax@14
  int v9; // ecx@17
  int v10; // eax@18
  char v11[16]; // [sp+Ch] [bp-64h]@1
  int v12; // [sp+20h] [bp-50h]@3
  int v13; // [sp+24h] [bp-4Ch]@3
  int v14; // [sp+28h] [bp-48h]@3
  int v15; // [sp+2Ch] [bp-44h]@3
  int v16; // [sp+30h] [bp-40h]@3
  int v17; // [sp+34h] [bp-3Ch]@3
  int v18; // [sp+38h] [bp-38h]@3
  int v19; // [sp+3Ch] [bp-34h]@3
  int v20; // [sp+40h] [bp-30h]@3
  int v21; // [sp+44h] [bp-2Ch]@3
  int v22; // [sp+48h] [bp-28h]@3
  int v23; // [sp+4Ch] [bp-24h]@3
  int v24; // [sp+50h] [bp-20h]@3
  int v25; // [sp+54h] [bp-1Ch]@3
  int v26; // [sp+58h] [bp-18h]@3
  int v27; // [sp+5Ch] [bp-14h]@3
  int v28; // [sp+60h] [bp-10h]@3
  int v29; // [sp+64h] [bp-Ch]@3
  int v30; // [sp+68h] [bp-8h]@3
  signed int v31; // [sp+6Ch] [bp-4h]@3

  inputPassword = *(_DWORD *)inputPassword;
  sub_401C00(&dword_4171C0, v11);             # continue input the password
  sub_401600(&unk_417130, strlen(v11));
  if ( strlen(v11) != 20 )
    exit(0);
  v16 = 562;
  v12 = 0;
  v13 = 0;
  v14 = 0;
  v15 = 0;
  v17 = 645;
  v18 = 756;
  v19 = 851;
  v20 = 920;
  v21 = 1017;
  v22 = 1132;
  v23 = 1253;
  v24 = 1348;
  v25 = 1427;
  v26 = 1531;
  v27 = 1626;
  v28 = 1697;
  v29 = 1808;
  v30 = 1908;
  v31 = 2033;
  v1 = 0;
  do
  {
    if ( v11[v1] != *((_BYTE *)&inputPassword + v1) ) # the v11[0:4] after prcess must equal the password'zctf'
      exit(0);
    ++v1;
  }
  while ( v1 < 4 );
  v2 = 5;
  v3 = &v16;
  do
  {
    v4 = 0;
    for ( i = 0; i < v2; ++i )  # pasword2[0:5].  the sum must be 562. which the [5] can be calculate
      v4 += v11[i];
    if ( *v3 != v4 )
      exit(0);
    ++v2;
    ++v3;
  }
  while ( v2 - 1 < 20 );
  v6 = (void *)sub_402380(&unk_417130, aZctf_youAreSoC);
  sub_401820(v6, 0xAu);
  v7 = 0;
  v8 = (int)((char *)v6 + *(_DWORD *)(*(_DWORD *)v6 + 4));
  if ( !(*(_BYTE *)(v8 + 4) & 6)
    && (*(int (__thiscall **)(_DWORD))(**(_DWORD **)(v8 + 40) + 44))(*(_DWORD *)(v8 + 40)) == -1 )
    v7 = 4;
  v9 = (int)((char *)v6 + *(_DWORD *)(*(_DWORD *)v6 + 4));
  if ( v7 )
  {
    v10 = v7 | *(_DWORD *)(v9 + 4);
    if ( !*(_DWORD *)(v9 + 40) )
      LOBYTE(v10) = v10 | 4;
    std::ios_base::clear((std::ios_base *)v9, v10, 0);
  }
}

6. 发现就是在保留了“zctf{”这几个字符的基础上,根据固定的数字列表,迭代求出来,很简单。


7.最终求得的就是flag“zctf{So_Easy_Oh_God}”。 感觉被主办方调戏了一把。= =。 so easy.


8. 完整的解析脚本。

s = ["My dear,for the hurt you sought to do me was is your good opinion.",
"I cannot choose the best.",
"My wishes are fools,they shout across thy song,my Master.",
"What you are you do not see,what you see is your shadow.",
"Do not seat your love upon a precipice because it is high.",
"Delusions of knowledge are like the fog of the morning.",
"Listen,my heart,to the whispers of the world with which it makes love to you.",
"Some unseen fingers,like an idle breeze,are playing upon my heart the music of the ripples.",
"Sorrow is hushed into peace in my heart like the evening among the silent trees.",
"Once we dreamt that we were strangers.",
"Her wishful face haunts my dreams like the rain at night.",
"If you shed tears when you miss the sun,you also miss the stars.",
"It is the tears of the earth that keep here smiles in bloom.",
"That I exist is a perpetual surprise which is life.",
"God expects answers for the flowers he sends us,not for the sun the earth.",
"O Beauty,find thyself in love,not in the flattery of thy mirror."
]


rS = []
MatrixA = []
MatrixB = [179334,175544,180760,182366,182850,180568,181440,178347,181577 \
    ,176475,174043,179882,178817,175345,178696,175320]

for i in range(len(s)):
    rS.append(s[i].replace(","," ").replace(".","").split(" "))
for i in range(len(rS)):
    tmps = list(''.join(rS[i])[:16])
    tmpsint = []
    for tmpstr in tmps:
        tmpsint.append(ord(tmpstr))
    MatrixA.append(tmpsint)
    # print tmpsint

# for i in range(len(MatrixA)):
#     for j in range(len(MatrixA[i])-1):
#         print str(MatrixA[i][j]) + "\t",
#     print str(MatrixA[i][len(MatrixA[i])-1])
# for Mb in MatrixB:
# 	print Mb
ans = [122,
99,
116,
102,
123,
87,
114,
111,
110,
103,
95,
70,
108,
97,
103,
125,
]
newans = []
nweint = []
for aa in ans:
	newans.append(chr(int(round(aa))))
print ''.join(newans)
print sum(ans[0:4])

Almost = [ 562,645,756,851,920,1017,1132,1253,1348,1427,1531,1626,1697,1808,1908,2033]
end = 5
start = ans[0:4]
theRest = []
for am in Almost:
	tt = am - sum(start) - sum(theRest)
	theRest.append(tt)
start.extend(theRest)
final = []
for tr in start:
	final.append(chr(tr))
print ''.join(final)


第一关还是简单, 后面的稍微看了一下,好久没弄逆向,对汇编不太熟练,发信ida要是不能够直接出伪代码,自己的速度就超级慢。
看来以后要加强自己这方面的软肋。
android的题目,到了so文件层面,对于一些直接爆出来的方法,比如,misc的最终要出来图片的方法,还是不熟。
目标赛棍going!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值