deedeedee crazy 寒假逆向生涯(11/100)
deedeedee
這題沒說法。。。直接用notepad++打開第二個文件,然后就看到了flag。。。。人傻了。。。
crazy
這題目呢,無殼,不難,直接拖進ida,主要是費眼。。。
查看偽代碼
int __cdecl main(int argc, const char **argv, const char **envp) {__int64 v3; // rax@1__int64 v4; // rax@1__int64 v5; // rax@1__int64 v6; // rax@1__int64 v7; // rax@1__int64 v8; // rax@1__int64 v9; // rax@1__int64 v10; // rax@1__int64 v11; // rax@2__int64 v12; // rax@2__int64 v13; // rax@2__int64 v14; // rax@2__int64 v15; // rax@2__int64 v16; // rax@2int result; // eax@3__int64 v18; // rcx@3char v19; // [sp+10h] [bp-130h]@1char v20; // [sp+30h] [bp-110h]@1char v21; // [sp+50h] [bp-F0h]@1char v22; // [sp+70h] [bp-D0h]@1char v23; // [sp+90h] [bp-B0h]@2char v24; // [sp+B0h] [bp-90h]@1__int64 v25; // [sp+128h] [bp-18h]@1v25 = *MK_FP(__FS__, 40LL);std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string((__int64)&v19,(__int64)argv,(__int64)envp);std::operator>><char,std::char_traits<char>,std::allocator<char>>(&std::cin, &v19);LODWORD(v3) = std::operator<<<std::char_traits<char>>((__int64)&std::cout,(__int64)"-------------------------------------------");std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);LODWORD(v4) = std::operator<<<std::char_traits<char>>((__int64)&std::cout, (__int64)"Quote from people's champ");std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>);LODWORD(v5) = std::operator<<<std::char_traits<char>>((__int64)&std::cout,(__int64)"-------------------------------------------");std::ostream::operator<<(v5, &std::endl<char,std::char_traits<char>>);LODWORD(v6) = std::operator<<<std::char_traits<char>>((__int64)&std::cout,(__int64)"*My goal was never to be the loudest or the craziest. It was to be the most entertaining.");std::ostream::operator<<(v6, &std::endl<char,std::char_traits<char>>);LODWORD(v7) = std::operator<<<std::char_traits<char>>((__int64)&std::cout,(__int64)"*Wrestling was like stand-up comedy for me.");std::ostream::operator<<(v7, &std::endl<char,std::char_traits<char>>);LODWORD(v8) = std::operator<<<std::char_traits<char>>((__int64)&std::cout,(__int64)"*I like to use the hard times in the past to motivate me today.");std::ostream::operator<<(v8, &std::endl<char,std::char_traits<char>>);LODWORD(v9) = std::operator<<<std::char_traits<char>>((__int64)&std::cout,(__int64)"-------------------------------------------");std::ostream::operator<<(v9, &std::endl<char,std::char_traits<char>>);HighTemplar::HighTemplar(&v24, &v19);LODWORD(v10) = std::operator<<<std::char_traits<char>>((__int64)&std::cout, (__int64)"Checking....");std::ostream::operator<<(v10, &std::endl<char,std::char_traits<char>>);std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string((__int64)&v20,(__int64)&v19);func1((__int64)&v21, (__int64)&v20);func2((__int64)&v22, (__int64)&v21);func3((__int64)&v22, 0);std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string((__int64)&v22);std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string((__int64)&v21);std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string((__int64)&v20);HighTemplar::calculate((HighTemplar *)&v24);if ( (unsigned int)HighTemplar::getSerial((HighTemplar *)&v24) == 0 ){LODWORD(v11) = std::operator<<<std::char_traits<char>>((__int64)&std::cout,(__int64)"/");std::ostream::operator<<(v11, &std::endl<char,std::char_traits<char>>);LODWORD(v12) = std::operator<<<std::char_traits<char>>((__int64)&std::cout,(__int64)"Do not be angry. Happy Hacking :)");std::ostream::operator<<(v12, &std::endl<char,std::char_traits<char>>);LODWORD(v13) = std::operator<<<std::char_traits<char>>((__int64)&std::cout,(__int64)"/");std::ostream::operator<<(v13, &std::endl<char,std::char_traits<char>>);ZN11HighTemplar7getFlagB5cxx11Ev((__int64)&v23, (__int64)&v24);LODWORD(v14) = std::operator<<<std::char_traits<char>>((__int64)&std::cout, (__int64)"flag{");LODWORD(v15) = std::operator<<<char,std::char_traits<char>,std::allocator<char>>(v14, (__int64)&v23);LODWORD(v16) = std::operator<<<std::char_traits<char>>(v15, (__int64)"}");std::ostream::operator<<(v16, &std::endl<char,std::char_traits<char>>);std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string((__int64)&v23);}HighTemplar::~HighTemplar((HighTemplar *)&v24);std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string((__int64)&v19);result = 0;v18 = *MK_FP(__FS__, 40LL) ^ v25;return result; }HighTemplar::HighTemplar((__int64)&v24, (__int64)&v19);
HighTemplar::calculate((HighTemplar *)&v24)
(unsigned int)HighTemplar::getSerial((HighTemplar *)&v24)
HighTemplar::HighTemplar((__int64)&v24, (__int64)&v19);
__int64 __fastcall HighTemplar::HighTemplar(__int64 a1, __int64 a2) {char v3; // [sp+17h] [bp-19h]@1__int64 v4; // [sp+18h] [bp-18h]@1v4 = *MK_FP(__FS__, 40LL);DarkTemplar::DarkTemplar((DarkTemplar *)a1);*(_QWORD *)a1 = &off_401EA0;*(_DWORD *)(a1 + 12) = 0;std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(a1 + 16, a2);std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(a1 + 48, a2);std::allocator<char>::allocator(&v3, a2);std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(a1 + 80,"327a6c4304ad5938eaf0efb6cc3e53dc",&v3);std::allocator<char>::~allocator(&v3);return *MK_FP(__FS__, 40LL) ^ v4; }這個函數作用:
初始化a1,那么它是如何初始化的呢?
下面只要抓住這三條輸入即可。。
然后只需要注意含有v24 ,v19地方即可
HighTemplar::calculate((HighTemplar *)&v24)
bool __fastcall HighTemplar::calculate(HighTemplar *this) {__int64 v1; // rax@1__int64 v2; // rax@2unsigned __int64 v3; // rax@5_BYTE *v4; // rax@6_BYTE *v5; // rbx@6_BYTE *v6; // rax@6unsigned __int64 v7; // rax@8bool result; // al@8_BYTE *v9; // rax@9_BYTE *v10; // rbx@9_BYTE *v11; // rax@9int i; // [sp+18h] [bp-18h]@4int j; // [sp+1Ch] [bp-14h]@7LODWORD(v1) = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length((char *)this + 16);if ( v1 != 32 ){LODWORD(v2) = std::operator<<<std::char_traits<char>>((__int64)&std::cout, (__int64)"Too short or too long");std::ostream::operator<<(v2, &std::endl<char,std::char_traits<char>>);exit(-1);}for ( i = 0; ; ++i ){LODWORD(v3) = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length((char *)this + 16);if ( i > v3 )break;LODWORD(v4) = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[]((char *)this + 16,i);v5 = v4;LODWORD(v6) = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[]((char *)this + 16,i);*v5 = (*v6 ^ 0x50) + 23;}for ( j = 0; ; ++j ){LODWORD(v7) = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length((char *)this + 16);result = j <= v7;if ( !result )break;LODWORD(v9) = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[]((char *)this + 16,j);v10 = v9;LODWORD(v11) = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[]((char *)this + 16,j);*v10 = (*v11 ^ 0x13) + 11;}return result; }首先,
LODWORD(v1) = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length((char *)this + 16);if ( v1 != 32 ){LODWORD(v2) = std::operator<<<std::char_traits<char>>((__int64)&std::cout, (__int64)"Too short or too long");std::ostream::operator<<(v2, &std::endl<char,std::char_traits<char>>);exit(-1);}來判斷輸入長度,是否符合,不符合的話,直接exit
下面兩個for循環的話,它是把輸入的第一串字符(因為它是(char *)this + 16,長度為32,即到(char *)this + 48的位置)經過一些簡單的異或操作變化之后,接下來變化之后肯定得拿去比較。。。。
至于為什么要這樣取的話,神操作。??赡芫幾g器有點傻,把
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[]( (char *)this + 16, i);多搞出一次了吧,別在意這些。。。
(unsigned int)HighTemplar::getSerial((HighTemplar *)&v24)
__int64 __fastcall HighTemplar::getSerial(HighTemplar *this) {unsigned __int64 v1; // rax@2char *v2; // rax@3char v3; // bl@3_BYTE *v4; // rax@3__int64 v5; // rax@4__int64 v6; // rax@4__int64 v7; // rax@5__int64 v8; // rax@5unsigned int i; // [sp+1Ch] [bp-14h]@1for ( i = 0; ; ++i ){LODWORD(v1) = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length((char *)this + 16);if ( (signed int)i >= v1 )break;LODWORD(v2) = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[]((char *)this + 80,(signed int)i);v3 = *v2;LODWORD(v4) = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[]((char *)this + 16,(signed int)i);if ( v3 != *v4 ){LODWORD(v7) = std::operator<<<std::char_traits<char>>((__int64)&std::cout, (__int64)"You did not pass ");LODWORD(v8) = std::ostream::operator<<(v7, i);std::ostream::operator<<(v8, &std::endl<char,std::char_traits<char>>);*((_DWORD *)this + 3) = 1;return *((_DWORD *)this + 3);}LODWORD(v5) = std::operator<<<std::char_traits<char>>((__int64)&std::cout, (__int64)"Pass ");LODWORD(v6) = std::ostream::operator<<(v5, i);std::ostream::operator<<(v6, &std::endl<char,std::char_traits<char>>);}return *((_DWORD *)this + 3); }這個函數作用呢,也就是驗證輸入的東西對不對。。。
for ( i = 0; ; ++i ){LODWORD(v1) = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length((char *)this + 16);if ( (signed int)i >= v1 )break;LODWORD(v2) = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[]((char *)this + 80,(signed int)i);v3 = *v2;LODWORD(v4) = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[]((char *)this + 16,(signed int)i);它把(char *)this + 16(輸入且經過一系列變換)和 (char *)this + 80(已知字符串賦值)兩個來相比,相同的話,這里比較就沒問題了。那我們只需要把這個已知字符串經過反向的異或操作變化回去不就行了嗎?是的,就是這樣
額外分析
那樣我們再來考慮一下,剛才是不是有一段(char *)this + 48,這段怎么沒用到呢?后面就是對這段進行分析,有興趣的可以繼續看。
ZN11HighTemplar7getFlagB5cxx11Ev((__int64)&v23, (__int64)&v24);
__int64 __fastcall ZN11HighTemplar7getFlagB5cxx11Ev(__int64 a1, __int64 a2) {std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(a1, a2 + 48);return a1; }這里就是把a2 + 48賦值給a1,即這里的v23,
然后再把它當flag去輸出就行。。
好家伙,三段字符,只需要輸入一段
一開始數據被分為三部分,
一部分(char *)this + 16賦值輸入,后面帶入算法;
一部分((char *)this + 48)賦值輸入,最后作為flag輸出;
一部分((char *)this + 80)賦值一個字符串,作為比較對象。
至于std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string((__int64)&v20,(__int64)&v19);這個函數,我感覺應該是借用v19來開辟一段空間給v20,并沒有把v19和v20之間扯上直接關系,所以下面三個func
func1((__int64)&v21, (__int64)&v20);func2((__int64)&v22, (__int64)&v21);func3((__int64)&v22, 0);與flag并無關系,而下面這三個是屬于析構函數,更無關系
GAMEOVER
#include <iostream> using namespace std; int main() {char b[32];char a[] = { "327a6c4304ad5938eaf0efb6cc3e53dc" };for (int i = 0; i < sizeof(a)-1; i++) {b[i] = ((((a[i] - 11) ^ 0x13) - 23) ^ 0x50);cout << b[i];} } flag{tMx~qdstOs~crvtwb~aOba}qddtbrtcd} 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的deedeedee crazy 寒假逆向生涯(11/100)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: notsequence 寒假逆向生涯(
- 下一篇: easyre-153 testre寒假