easyre-153 testre寒假逆向生涯(13/100)
easyre-153
簡單題目,流程走起,首先查殼,
脫殼
upx殼,利用工具把它脫掉
ida靜態分析
int __cdecl main(int argc, const char **argv, const char **envp) {int result; // eax@9int v4; // edx@9int v5; // [sp+18h] [bp-38h]@1int v6; // [sp+1Ch] [bp-34h]@2__pid_t v7; // [sp+20h] [bp-30h]@1int v8; // [sp+24h] [bp-2Ch]@4__int16 v9; // [sp+2Eh] [bp-22h]@4int v10; // [sp+4Ch] [bp-4h]@1v10 = *MK_FP(__GS__, 20);pipe(&v5);v7 = fork();if ( !v7 ){puts("\nOMG!!!! I forgot kid's id");write(v6, "69800876143568214356928753", 0x1Du);puts("Ready to exit ");exit(0);}read(v5, &v9, 0x1Du);__isoc99_scanf("%d", &v8);if ( v8 == v7 ){if ( (*(_DWORD *)((char *)lol + 3) & 0xFF) == 204 ){puts(":D");exit(1);}printf("\nYou got the key\n ");lol((int)&v9);}wait(0);result = 0;v4 = *MK_FP(__GS__, 20) ^ v10;return result; }這里需要介紹一點東西pipe函數和fork函數
pipe函數:
函數聲明:
- pipe函數可用于創建一個管道,以實現進程間的通信。
- pipe函數定義中的fd參數是一個大小為2的一個數組類型的指針(在這里呢也就是v5和v6)。該函數成功時返回0,并將一對打開的文件描述符值填入fd參數指向的數組。失敗時返回 -1并設置errno。
- 通過pipe函數創建的這兩個文件描述符 fd[0] 和 fd[1] 分別構成管道的兩端,往 fd[1] 寫入的數據可以從 fd[0] 讀出。并且 fd[1] 一端只能進行寫操作,fd[0] 一端只能進行讀操作,不能反過來使用。要實現雙向數據傳輸,可以使用兩個管道。
fork函數
- 在父進程中,fork返回新創建子進程的進程ID;
- 在子進程中,fork返回0;
- 如果出現錯誤,fork返回一個負值;
在這里呢,需要寫入操作,即在子進程中時,fork返回0。
看到這句
然后呢,進行讀操作,都出來之后猜到了 lol((int)&v9);藏的就是flag。
看到了讀取出來的東西,然后進行一系列的變換得到一個 7個char,也就是flag
GAMEOVER
#include <iostream> using namespace std; int main() {char b[7] = {0};char a[] = { "69800876143568214356928753" };b[0] = char(2 * int(a[1]));b[1] = char(int(a[4])+int(a[5]));b[2] = char(int(a[8]) + int(a[9]));b[3] = char(2*int(a[12])) ;b[4] = char(int(a[18]) + int(a[17]));b[5] = char(int(a[10]) + int(a[21]));b[6] = char(int(a[9]) + int(a[25]));cout << "RCTF{";for (int i = 0; i < 7; i++) {cout <<b[i];}cout << "}"; }testre
餐前點心(base58)
首先得跟大家說一下,什么是base58
base58加密與其他base系列不同的是:
base64是每6bit位一個映射
base32是每5bit位一個映射
base16是每bit4位一個映射
而base58不是根據bit位而來 而是直接模58而映射的
Base58的碼表:123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ
9位數字以及去掉了英文字母容易造成混淆的字母(0:數字零,O:大寫O,I:大寫i,l:小寫L,以及’+‘和’ /’)所組成
編碼流程:
① 將所要編碼的字符串轉為ASCII碼(ASCII碼實際上也就是256進制的數)
例如將”ABD”轉為 65 66 68
② 然后再將256進制轉為10進制數,65256256+66*256+68=4276804
③ 最后將十進制數轉為58進制,即模58轉化,最后得到21 53 20 0
④ 根據21 53 20 0查表中所對應的字符得到base58編碼的密文:nVm1
解碼流程與其編碼流程相反
總結,編碼就是將所要加密的字符先轉256進制,再轉10進制再轉為58進制,最后查碼表;解碼就是查碼表得到58進制,再轉10進制最后再轉256進制最后通過ascii碼表轉為字符
base58編碼實現
int main() {char text[] = "xunmeng";const int len = strlen(text) * 138 / 100 + 1;char base58[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";long long sum = 0;char encryption[7 * 138 / 100 + 1];int index = 0;for (int i = 0; i < strlen(text); i++) {sum += text[i] * pow(256, strlen(text) - 1 - i);}// printf("%d\n", sum);for (int i = len - 1; i >= 0; i--) {encryption[i] = base58[sum % 58];sum /= 58;if (sum == 0)break;}for (int i = 0; i <= len - 1; i++) {cout << encryption[i];}while (index < strlen(text)) {int each = text[index];for (int i = len - 1;; i--) {each += encryption[i] * 256;encryption[i] = each % 58;each /= 58;if (each == 0)break;}} }注意點:
base58編碼后的字符長度是編碼之前的1.37倍,即之前長度 * log(2)256 / log(2)(58) + 1
開戰
此題呢,是2019西湖論劍比賽題目。。長嘆一句。。
直奔主題,拖進ida后,查看到有兩個重要的函數,
v3 = sub_400D00((__int64)&v8, 0x11uLL);
主要是用來進行初始化的,沒有什么好說的。
v5 = sub_400700(ptr, &v7, (__int64)&v8, 0x10uLL);
__int64 __fastcall sub_400700(void *a1, _QWORD *a2, __int64 a3, size_t a4) {__int64 *v4; // rcx@28__int64 v6; // [sp+0h] [bp-C0h]@1int c; // [sp+8h] [bp-B8h]@25char v8; // [sp+Fh] [bp-B1h]@18int v9; // [sp+10h] [bp-B0h]@14bool v10; // [sp+17h] [bp-A9h]@11__int64 *v11; // [sp+18h] [bp-A8h]@8char v12; // [sp+27h] [bp-99h]@4int v13; // [sp+28h] [bp-98h]@3int v14; // [sp+2Ch] [bp-94h]@23unsigned __int64 i; // [sp+30h] [bp-90h]@1size_t n; // [sp+38h] [bp-88h]@8size_t v17; // [sp+40h] [bp-80h]@1size_t v18; // [sp+48h] [bp-78h]@8size_t j; // [sp+50h] [bp-70h]@10size_t v20; // [sp+58h] [bp-68h]@8int v21; // [sp+64h] [bp-5Ch]@10unsigned __int64 v22; // [sp+68h] [bp-58h]@1int v23; // [sp+74h] [bp-4Ch]@8__int64 *v24; // [sp+78h] [bp-48h]@1__int64 v25; // [sp+80h] [bp-40h]@1void *v26; // [sp+88h] [bp-38h]@1int v27; // [sp+94h] [bp-2Ch]@1size_t v28; // [sp+98h] [bp-28h]@1__int64 v29; // [sp+A0h] [bp-20h]@1_QWORD *v30; // [sp+A8h] [bp-18h]@1void *s; // [sp+B0h] [bp-10h]@1char v32; // [sp+BFh] [bp-1h]@23s = a1;v30 = a2;v29 = a3;v28 = a4;v27 = -559038737;v26 = malloc(0x100uLL);v25 = v29;v24 = &v6;v22 = 0LL;v17 = 0LL;for ( i = 0LL; i < v28; ++i ){v13 = *(_BYTE *)(v25 + i);*((_BYTE *)v26 + i) = byte_400E90[i % 0x1D] ^ v13;*((_BYTE *)v26 + i) += *(_BYTE *)(v25 + i);}while ( 1 ){v12 = 0;if ( v17 < v28 )v12 = ~(*(_BYTE *)(v25 + v17) != 0);if ( !(v12 & 1) )break;++v17;}n = ((unsigned __int64)(2951479051793528259LL * (unsigned __int128)(138 * (v28 - v17) >> 2) >> 64) >> 2) + 1;v23 = ((unsigned __int64)(0x0AAAAAAAAAAAAAAABLL * (unsigned __int128)((v17 + v28) << 6) >> 64) >> 5) - 1;v11 = (__int64 *)((char *)&v6- ((((unsigned __int64)(2951479051793528259LL * (unsigned __int128)(138 * (v28 - v17) >> 2) >> 64) >> 2)+ 16) & 0xFFFFFFFFFFFFFFF0LL));memset(v11, 0, n);v20 = v17;v18 = n - 1;while ( v20 < v28 ){v21 = *(_BYTE *)(v25 + v20);for ( j = n - 1; ; --j ){v10 = 1;if ( j <= v18 )v10 = v21 != 0;if ( !v10 )break;v22 = *((_BYTE *)v11 + j) << 6;v21 += *((_BYTE *)v11 + j) << 8;v9 = 64;*((_BYTE *)v11 + j) = v21 % 58;*((_BYTE *)v26 + j) = v22 & 0x3F;v22 >>= 6;v21 /= 58;v27 /= v9;if ( !j )break;}++v20;v18 = j;}for ( j = 0LL; ; ++j ){v8 = 0;if ( j < n )v8 = ~(*((_BYTE *)v11 + j) != 0);if ( !(v8 & 1) )break;}if ( *v30 > n + v17 - j ){if ( v17 ){c = 61;memset(s, 49, v17);memset(v26, c, v17);}v20 = v17;while ( j < n ){v4 = v11;*((_BYTE *)s + v20) = byte_400EB0[(unsigned __int64)*((_BYTE *)v11 + j)];*((_BYTE *)v26 + v20++) = byte_400EF0[(unsigned __int64)*((_BYTE *)v4 + j++)];}*((_BYTE *)s + v20) = 0;*v30 = v20 + 1;if ( !strncmp((const char *)s, "D9", 2uLL)&& !strncmp((const char *)s + 20, "Mp", 2uLL)&& !strncmp((const char *)s + 18, "MR", 2uLL)&& !strncmp((const char *)s + 2, "cS9N", 4uLL)&& !strncmp((const char *)s + 6, "9iHjM", 5uLL)&& !strncmp((const char *)s + 11, "LTdA8YS", 7uLL) ){HIDWORD(v6) = puts("correct!");}v32 = 1;v14 = 1;}else{*v30 = n + v17 - j + 1;v32 = 0;v14 = 1;}return v32 & 1; }直接找到最關鍵的地方
if ( !strncmp((const char *)s, "D9", 2uLL)&& !strncmp((const char *)s + 20, "Mp", 2uLL)&& !strncmp((const char *)s + 18, "MR", 2uLL)&& !strncmp((const char *)s + 2, "cS9N", 4uLL)&& !strncmp((const char *)s + 6, "9iHjM", 5uLL)&& !strncmp((const char *)s + 11, "LTdA8YS", 7uLL) ){HIDWORD(v6) = puts("correct!");}湊出一個 字符串D9cS9N9iHjMLTdA8YSMRMp,即s和字符串比較,反推回去可知s是與v11相關
*((_BYTE *)s + v20) = byte_400EB0[(unsigned __int64)*((_BYTE *)v11 + j)];byte_400EB0[]數組為
0x31是字符1,所以這個數組不就是base58表嗎?
然后又來尋找相關代碼
while ( v20 < v28 ){v21 = *(_BYTE *)(v25 + v20);for ( j = n - 1; ; --j ){v10 = 1;if ( j <= v18 )v10 = v21 != 0;if ( !v10 )break;v22 = *((_BYTE *)v11 + j) << 6;v21 += *((_BYTE *)v11 + j) << 8;v9 = 64;*((_BYTE *)v11 + j) = v21 % 58;*((_BYTE *)v26 + j) = v22 & 0x3F;v22 >>= 6;v21 /= 58;v27 /= v9;if ( !j )break;}++v20;v18 = j;}分析知是base58編碼,然后通過網站解密
總結
以上是生活随笔為你收集整理的easyre-153 testre寒假逆向生涯(13/100)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: deedeedee crazy 寒
- 下一篇: XCTF easyCpp buu [MR