title: BUU-RE-刮开有奖-WinMain
tags:

  • CTF
  • RE
  • BUU
    abbrlink: ‘10638684’
    date: 2020-12-25 11:26:07

WinMain函数参数介绍

int WINAPI WinMain(

HINSTANCE hInstance, // handle to current instance

HINSTANCE hPrevInstance, // handle to previous instance

LPSTR lpCmdLine, // command line

int nCmdShow // show state

);

WinMain函数接收4个参数,这些参数都是在系统调用WinMain函数时,传递给应用程序的。

第一个参数hInstance表示该程序当前运行的实例的句柄,这是一个数值。当程序在Windows下运行时,它唯一标识运行中的实例(注意,只有运行中的程序实例,才有实例句柄)。一个应用程序可以运行多个实例,每运行一个实例,系统都会给该实例分配一个句柄值,并通过hInstance参数传递给WinMain函数。

第二个参数hPrevInstance表示当前实例的前一个实例的句柄。通过查看MSDN我们可以知道,在Win32环境下,这个参数总是NULL,即在Win32环境下,这个参数不再起作用。

第三个参数lpCmdLine是一个以空终止的字符串,指定传递给应用程序的命令行参数。例如:在D盘下有一个sunxin.txt文件,当我们用鼠标双击这个文件时将启动记事本程序(notepad.exe),此时系统会将D:\sunxin.txt作为命令行参数传递给记事本程序的WinMain函数,记事本程序在得到这个文件的全路径名后,就在窗口中显示该文件的内容。要在VC++开发环境中向应用程序传递参数,可以单击菜单【Project】→【Settings】,选择“Debug”选项卡,在“Program arguments”编辑框中输入你想传递给应用程序的参数。

第四个参数nCmdShow指定程序的窗口应该如何显示,例如最大化、最小化、隐藏等。这个参数的值由该程序的调用者所指定,应用程序通常不需要去理会这个参数的值。

解题

首先对WinMain进行分析BUU-RE-刮开有奖-WinMain - 图1

查看DialogFunc参数

  1. BOOL __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4)
  2. {
  3. const char *v4; // esi
  4. const char *v5; // edi
  5. int v7[11]; // [esp+8h] [ebp-20030h]
  6. CHAR String[9]; // [esp+34h] [ebp-20004h]
  7. CHAR v9[3]; // [esp+10034h] [ebp-10004h]
  8. if ( a2 == 272 )
  9. return 1;
  10. if ( a2 != 273 )
  11. return 0; //
  12. // a2 = 273
  13. if ( a3 == 1001 ) // a3 = 1001
  14. {
  15. memset(String, 0, 0xFFFFu); // 给string清零
  16. GetDlgItemTextA(hDlg, 1000, String, 0xFFFF);// 获取对话框文本,然后赋值给string
  17. if ( strlen(String) == 8 ) // string的长度要为8
  18. {
  19. v7[0] = 90;
  20. v7[1] = 74;
  21. v7[2] = 83;
  22. v7[3] = 69;
  23. v7[4] = 67;
  24. v7[5] = 97;
  25. v7[6] = 78;
  26. v7[7] = 72;
  27. v7[8] = 51;
  28. v7[9] = 110;
  29. v7[10] = 103;
  30. sub_4010F0(v7, 0, 10); // 对v7进行处理,处理后的数据
  31. // 51 67 69 72 74 78 83 90 97 103 110
  32. memset(v9, 0, 0xFFFFu); // 给v16清零
  33. v9[0] = String[5];
  34. v9[2] = String[7];
  35. v9[1] = String[6];
  36. v4 = sub_401000(v9, strlen(v9)); // 对v9进行base64加密然后传递给v4
  37. memset(v9, 0, 0xFFFFu); // 给v9清零
  38. v9[1] = String[3];
  39. v9[0] = String[2];
  40. v9[2] = String[4];
  41. v5 = sub_401000(v9, strlen(v9)); // 对v9进行base64加密然后传递给v4
  42. if ( String[0] == v7[0] + 34 // string[0] = 'U'
  43. && String[1] == v7[4] // string[1] = 'J'
  44. && 4 * String[2] - 141 == 3 * v7[2] // string[2] = 'W'
  45. && String[3] / 4 == 2 * (v7[7] / 9) // string[3] = 'P'
  46. && !strcmp(v4, "ak1w") // v4 = "ak1w"
  47. && !strcmp(
  48. v5, // v5 = "V1Ax"
  49. "V1Ax") )
  50. {
  51. MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);
  52. }
  53. }
  54. return 0;
  55. }
  56. if ( a3 != 1 && a3 != 2 )
  57. return 0;
  58. EndDialog(hDlg, a3);
  59. return 1;
  60. }

其中sub_4010F0函数参数已知,可以直接求出其处理结果

转换为C语言脚本

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. // a1 为 v7对应地址
  4. // a2 = 0
  5. // a3 = 10
  6. int __cdecl sub_4010F0(int *a1, int a2, int a3)
  7. {
  8. int result; // eax
  9. int i; // esi
  10. int v5; // ecx
  11. int v6; // edx
  12. result = a3; // result = 10
  13. for ( i = a2; i <= a3; a2 = i ) // i=0;i<=10;a2=i
  14. {
  15. v5 = i;
  16. v6 = a1[i]; // 遍历a1对应地址的元素
  17. if ( a2 < result && i < result ) // a2<10 并且 i<10
  18. {
  19. do
  20. {
  21. if ( v6 > a1[result] ) // 如果a1[i] > a1[result]
  22. {
  23. if ( i >= result )
  24. break; // 如果i>=result则退出循环
  25. ++i; // 给i+1
  26. a1[v5] = a1[result]; // 让a1[1] = a1[result]
  27. if ( i >= result )
  28. break; // 如果i>=result则退出循环 重复
  29. while ( a1[i] <= v6 ) // 当a1[i] <= v6 此循环一定成立
  30. {
  31. if ( ++i >= result ) // 如果i = result - 1
  32. goto LABEL_13;
  33. }
  34. if ( i >= result )
  35. break;
  36. v5 = i;
  37. a1[result] = a1[i];
  38. }
  39. --result; // result减一
  40. }
  41. while ( i < result );
  42. }
  43. LABEL_13:
  44. a1[result] = v6; // 让a1[result] = 之前的a1[i]
  45. sub_4010F0(a1, a2, i - 1); // 进行递归……
  46. result = a3;
  47. ++i;
  48. }
  49. return result;
  50. }
  51. int main()
  52. {
  53. int v7[11]={90,74,83,69,67,97,78,72,51,110,103};
  54. sub_4010F0(v7,0,10);
  55. for(int i=0;i<11;i++)
  56. {
  57. printf("%c ", v7[i]);
  58. }
  59. return 0;
  60. }

得到如下结果

  1. 3 C E H J N S Z a g n
  1. // a1 为 v7对应地址
  2. // a2 = 0
  3. // a3 = 10
  4. int __cdecl sub_4010F0(int *a1, int a2, int a3)
  5. {
  6. int result; // eax
  7. int i; // esi
  8. int v5; // ecx
  9. int v6; // edx
  10. result = a3; // result = 10
  11. for ( i = a2; i <= a3; a2 = i ) // i=0;i<=10;a2=i
  12. {
  13. v5 = i;
  14. v6 = a1[i]; // 遍历a1对应地址的元素
  15. if ( a2 < result && i < result ) // a2<10 并且 i<10
  16. {
  17. do
  18. {
  19. if ( v6 > a1[result] ) // 如果a1[i] > a1[result]
  20. {
  21. if ( i >= result )
  22. break; // 如果i>=result则退出循环
  23. ++i; // 给i+1
  24. a1[v5] = a1[result]; // 让a1[1] = a1[result]
  25. if ( i >= result )
  26. break; // 如果i>=result则退出循环 重复
  27. while ( a1[i] <= v6 ) // 当a1[i] <= v6 此循环一定成立
  28. {
  29. if ( ++i >= result ) // 如果i = result - 1
  30. goto LABEL_13;
  31. }
  32. if ( i >= result )
  33. break;
  34. v5 = i;
  35. a1[result] = a1[i];
  36. }
  37. --result; // result减一
  38. }
  39. while ( i < result );
  40. }
  41. LABEL_13:
  42. a1[result] = v6; // 让a1[result] = 之前的a1[i]
  43. sub_4010F0(a1, a2, i - 1); // 进行递归……
  44. result = a3;
  45. ++i;
  46. }
  47. return result;
  48. }

对两个比较的字符串分别进行base64解密(byte内有明显的base64加密提示)

开头两个字符分别对应的是’3’+34后的字’U’,和对应栈内v7[4]=’J’

得到

  1. UJWP1jMp