2019安恆二月賽逆向題目cpp詳解

本人首發在先知社區
https://xz.aliyun.com/t/4282

2019安恆二月賽的一道題目
這道題目運行,輸入11111111111 回車,程序直接關閉,沒有任何提示信息

image.png
Exeinfo PE查殼發現是一個C++程序並且沒有加殼

image.png
IDA x32載入程序 shift + F12查看有沒有什麼可以字符串
發現一個’Please input:’
雙擊進去 接着雙擊引用
image.png

image.png
程序流程圖貌似很簡單的樣子

image.png
F5查看僞代碼
進行簡單分析 Src是一個字符串數組 unsigned int是錯誤的
image.png
我們雙擊Src看下在程序中的位置

image.png
發現是在.data段也就是數據段(data segment),通常是指用來存放程序中已初始化的全局變量的一塊內存區域,那Src是一個32位的全局字符串數組變量

雙擊sub_411302()進去 發現最後返回的是中間的參數 也就是result
image.png
雙擊sub_411352() 進行分析

image.png
接着雙擊sub_413910()

int __usercall sub_413910@<eax>(int a1@<xmm0>, char *Str)
{
  char v2; // cl
  size_t i; // [esp+D0h] [ebp-8h]

  sub_4112F8((int)&unk_421008);
  for ( i = 0; i < j_strlen(Str); ++i )         // 將Str這個字符串分爲三組 分別與0x1f,0x20,0x21進行異或
  {
    if ( i % 3 )
    {
      if ( i % 3 == 1 )
        v2 = Str[i] ^ 0x20;
      else
        v2 = Str[i] ^ 0x21;
      Str[i] = v2;
    }
    else
    {
      Str[i] ^= 0x1Fu;
    }
  }
  return sub_411302(1, (int)Str, a1);           // 最後返回a1
}

總的分析

int __usercall sub_413E30@<eax>(int a1@<xmm0>)
{
  int v1; // eax
  int v3; // [esp+0h] [ebp-CCh]

  sub_4112F8((int)&unk_421008);
  sub_411276(std::cout, "Please input: ");      // cout輸出提示信息
  scanf((const char *)&my_input, (unsigned int)Src, 32);// scanf輸入  保存在Src
  if ( j_strlen(Src) >= 14 && j_strlen(Src) <= 32 )// 判斷Src的長度是否滿足大於等於14,小於等於32 若滿足,就繼續
  {
    v1 = strcpy_s(Str, 32u, Src);               // 用strcpy_s()函數拷貝Src到Str
    sub_411302(&v3 == &v3, v1, a1);
    sub_411352(a1, Str);                        // 對Str進行異或操作  返回a1
  }
  return sub_411302(1, 0, a1);                  // 返回0 相當於return 0
}

感覺程序沒有結束但就是找不到下面的代碼
看了官方WP
瞭解到可以查看Str的引用
因爲後面一直是對Str進行處理 所以可以猜測後續還會對他進行處理

image.png
點擊任意一個Str 點擊X 可以查看到第三條是還未分析的
我們雙擊進去 可以發現有兩個Str

image.png
這時候我們就是該找到新Str的來源 但是我的IDA好像找不到其他引用
所以換個思路
我們可以看 unk_421008 所在區域 一般都是在一塊的 點擊它 按X

image.png
可以發現向上遊好多引用
一個一個看 最後可以發現最上面這個 就是我們要找的

image.png
雙擊可以看到

image.png

那麼我們就可以編寫腳本解出flag

str1 = ''
str2 = 'access denieda'
flag = ''
for i in range(len(str2)):
  str1 += chr(ord(str2[i])^i)
# print str1
#abafwv&cmgcnhl
for i in range(len(str2)):
  if i % 3 == 0:
    flag+= chr(ord(str1[i])^0x1f)
  elif i % 3 == 1:
    flag+= chr(ord(str1[i])^0x20)
  elif i % 3 == 2:
    flag+= chr(ord(str1[i])^0x21)
print flag
#~B@yWW9CLxCOwL

總結:當沒有頭緒的時候,可以查看變量或字符串的引用

這道題有涉及到虛函數表的知識
參考鏈接:https://www.linkedbyx.com/taskinfo/443/detail

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章