上次参加2019看雪CTF 晋级赛Q2卡在了这道题上,虽然逆出算法,但是方程不会解,哈哈哈哈,果然数学知识很重要呀,现在记录一下。

首先根据关键信息,根据错误提示字符串定位到这里:

 1 int __thiscall guanjian_401EA0(CWnd *this)
2 {
3 CWnd *v1; // esi
4 int index; // eax
5 WCHAR String; // [esp+Ch] [ebp-310h]
6 char v5; // [esp+Eh] [ebp-30Eh]
7 char ptr; // [esp+20Ch] [ebp-110h]
8 char v7; // [esp+20Dh] [ebp-10Fh]
9 DWORD v8; // [esp+30Ch] [ebp-10h]
10 CWnd *v9; // [esp+310h] [ebp-Ch]
11 int v10; // [esp+314h] [ebp-8h]
12 DWORD flOldProtect; // [esp+318h] [ebp-4h]
13
14 v1 = this;
15 v9 = this;
16 String = 0;
17 memset(&v5, 0, 0x1FEu);
18 ptr = 0;
19 memset(&v7, 0, 0xFFu);
20 CWnd::GetDlgItemTextW(v1, 1000, &String, 20);
21 if ( wcslen(&String) == 16 )
22 {
23 index = 0;
24 while ( !(*(&String + index) & 0xFF00) )
25 {
26 *(&ptr + index) = *((_BYTE *)&String + 2 * index);
27 if ( ++index >= 16 )
28 {
29 v8 = 64;
30 flOldProtect = 0;
31 VirtualProtect(sub_9D10E0, 0xD17u, 0x40u, &flOldProtect);// BOOL VirtualProtect(
32 // LPVOID lpAddress,
33 // DWORD dwSize,
34 // DWORD flNewProtect,
35 // PDWORD lpflOldProtect
36 // lpAddress,要改变属性的内存起始地址。
37 //
38 // dwSize,要改变属性的内存区域大小。
39 //
40 // flNewProtect,内存新的属性类型,设置为PAGE_EXECUTE_READWRITE(0x40)时该内存页为可读可写可执行。
41 //
42 // pflOldProtect,内存原始属性类型保存地址。
43 //
44 //
45 GetLastError();
46 qmemcpy(sub_9D10E0, byte_B347B8, 0x330u);
47 VirtualProtect(sub_9D10E0, 0xD17u, flOldProtect, &v8);
48 if ( !GetLastError() )
49 {
50 v10 = 0;
51 v10 = sub_9D10E0();
52 if ( v10 == 1 )
53 return CWnd::MessageBoxW(v9, L"Congratulations! You are right!", 0, 0);
54 }
55 v1 = v9;
56 return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
57 }
58 }
59 }
60 return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
61 }
注意到运行时先修改sub_9D10E0()代码段,然后再运行sub_9D10E0(),我们动态调试,dump出修改完成的sub_9D10E0()代码段
  1 int __cdecl sub_9D10E0(char *input)
2 {
3 signed int i; // eax
4 char v2; // cl
5 signed int v3; // ecx
6 signed int v4; // eax
7 signed int low_index; // eax
8 signed int j; // esi
9 signed int k; // ecx
10 __int16 v8; // dx
11 char *buffer_ptr_; // edi
12 __int16 v10; // ax
13 signed int temp_1; // eax
14 signed int m_1; // ecx
15 unsigned __int16 t_3; // bx
16 signed int j_1; // esi
17 signed int k_1; // ecx
18 __int16 v16; // dx
19 char *buffer_ptr; // edi
20 __int16 t_4; // ax
21 signed int t; // eax
22 signed int m; // ecx
23 unsigned __int16 temp; // bx
24 unsigned int t_1; // eax
25 signed int i_2; // ecx
26 unsigned __int16 temp_2; // dx
27 char f; // dl
28 signed int i_1; // eax
29 __int16 t_2; // si
30 int index; // eax
31 char s_xor[17]; // [esp+8h] [ebp-90h]
32 int v31; // [esp+1Ch] [ebp-7Ch]
33 int v32; // [esp+20h] [ebp-78h]
34 int v33; // [esp+24h] [ebp-74h]
35 char x[8]; // [esp+28h] [ebp-70h]
36 char buffer[16]; // [esp+30h] [ebp-68h]
37 char y[8]; // [esp+40h] [ebp-58h]
38 char yy7_result[17]; // [esp+48h] [ebp-50h]
39 char result[17]; // [esp+5Ch] [ebp-3Ch]
40 char xx_result[17]; // [esp+70h] [ebp-28h]
41 char yy_result[17]; // [esp+84h] [ebp-14h]
42
43 s_xor[4] = 0x81u;
44 s_xor[11] = 0x81u;
45 i = 0;
46 s_xor[0] = 0x16;
47 s_xor[1] = -106;
48 s_xor[2] = -116;
49 s_xor[3] = -29;
50 s_xor[5] = -104;
51 s_xor[6] = 110;
52 s_xor[7] = 100;
53 s_xor[8] = 0x84u;
54 s_xor[9] = 8;
55 s_xor[10] = -36;
56 s_xor[12] = 0xBEu;
57 s_xor[13] = 77;
58 s_xor[14] = 72;
59 s_xor[15] = 79;
60 *(_DWORD *)&s_xor[16] = 0;
61 v31 = 0;
62 v32 = 0;
63 v33 = 0;
64 *(_DWORD *)x = 0;
65 *(_DWORD *)&x[4] = 0;
66 *(_DWORD *)y = 0;
67 *(_DWORD *)&y[4] = 0;
68 do
69 { // 先将输入分成两部分,记为x,y,然后进行异或操作,
70 v2 = s_xor[i + 8] ^ input[i + 8]; // 从输入的第9位开始处理,索引8-15
71 // 异或
72 x[i] = s_xor[i] ^ s_xor[i + input - s_xor]; // 输入的前8位
73 // 异或
74 y[i++] = v2;
75 }
76 while ( i < 8 );
77 *(_DWORD *)s_xor = 0;
78 *(_DWORD *)xx_result = 0;
79 *(_DWORD *)&xx_result[4] = 0;
80 *(_DWORD *)&xx_result[8] = 0;
81 *(_DWORD *)&xx_result[12] = 0;
82 xx_result[16] = 0;
83 *(_DWORD *)yy_result = 0;
84 *(_DWORD *)&yy_result[4] = 0;
85 *(_DWORD *)&yy_result[8] = 0;
86 *(_DWORD *)&yy_result[12] = 0;
87 yy_result[16] = 0;
88 *(_DWORD *)yy7_result = 0;
89 *(_DWORD *)&yy7_result[4] = 0;
90 *(_DWORD *)&yy7_result[8] = 0;
91 *(_DWORD *)&yy7_result[12] = 0;
92 yy7_result[16] = 0;
93 *(_DWORD *)result = 0;
94 *(_DWORD *)&result[4] = 0;
95 *(_DWORD *)&result[8] = 0;
96 *(_DWORD *)&result[12] = 0;
97 result[16] = 0;
98 *(_DWORD *)&s_xor[4] = 0;
99 *(_DWORD *)&s_xor[8] = 0;
100 *(_DWORD *)&s_xor[12] = 0;
101 s_xor[16] = 0;
102 v3 = 8;
103 s_xor[0] = 8;
104 v4 = 7;
105 do
106 {
107 if ( x[v4] ) // x[7]!=0
108 break;
109 --v3;
110 --v4;
111 }
112 while ( v4 >= 0 );
113 if ( v3 == 8 )
114 {
115 low_index = 7;
116 do
117 {
118 if ( y[low_index] ) // y[7]!=0
119 break;
120 --v3;
121 --low_index;
122 }
123 while ( low_index >= 0 ); // 输入为16位
124 if ( v3 == 8 && !(x[7] & 0xF0) ) // 第8位<0x10
125 {
126 j = 0;
127 do
128 {
129 *(_DWORD *)buffer = 0;
130 *(_DWORD *)&buffer[4] = 0;
131 *(_DWORD *)&buffer[8] = 0;
132 *(_DWORD *)&buffer[12] = 0;
133 k = 0;
134 v8 = (unsigned __int8)x[j];
135 buffer_ptr_ = &buffer[j];
136 do
137 {
138 v10 = (unsigned __int8)buffer[j + 8] + v8 * (unsigned __int8)x[k];
139 buffer_ptr_[k] = buffer[j + 8] + v8 * x[k];
140 ++k;
141 buffer[j + 8] = HIBYTE(v10);
142 }
143 while ( k < 8 );
144 LOBYTE(temp_1) = 0;
145 m_1 = 0;
146 do
147 {
148 t_3 = (char)temp_1 + (unsigned __int8)xx_result[m_1 + j] + (unsigned __int8)buffer_ptr_[m_1];
149 xx_result[m_1++ + j] = t_3;
150 temp_1 = (signed int)t_3 >> 8;
151 }
152 while ( m_1 < 9 );
153 ++j; // 先按字节乘,再加进位,和手算乘法原理一致
154 }
155 while ( j < 8 ); // 通过两层循环其实是为了计算大数相乘,这里算出x^2
156 j_1 = 0;
157 do
158 {
159 *(_DWORD *)buffer = 0;
160 *(_DWORD *)&buffer[4] = 0;
161 *(_DWORD *)&buffer[8] = 0;
162 *(_DWORD *)&buffer[12] = 0;
163 k_1 = 0;
164 v16 = (unsigned __int8)y[j_1];
165 buffer_ptr = &buffer[j_1];
166 do
167 {
168 t_4 = (unsigned __int8)buffer[j_1 + 8] + v16 * (unsigned __int8)y[k_1];
169 buffer_ptr[k_1] = buffer[j_1 + 8] + v16 * y[k_1];
170 ++k_1;
171 buffer[j_1 + 8] = HIBYTE(t_4);
172 }
173 while ( k_1 < 8 );
174 LOBYTE(t) = 0;
175 m = 0;
176 do
177 {
178 temp = (char)t + (unsigned __int8)yy_result[m + j_1] + (unsigned __int8)buffer_ptr[m];
179 yy_result[m++ + j_1] = temp;
180 t = (signed int)temp >> 8;
181 }
182 while ( m < 9 );
183 ++j_1; // 这里计算出y^2
184 }
185 while ( j_1 < 8 );
186 LOBYTE(t_1) = yy7_result[16];
187 i_2 = 0;
188 do
189 { // 这里计算7*y^2
190 temp_2 = (unsigned __int8)t_1 + 7 * (unsigned __int8)yy_result[i_2];
191 yy7_result[i_2++] = temp_2;
192 t_1 = (unsigned int)temp_2 >> 8;
193 }
194 while ( i_2 < 17 );
195 yy7_result[16] = HIBYTE(temp_2);
196 f = 0;
197 i_1 = 0;
198 do
199 {
200 t_2 = (unsigned __int8)xx_result[i_1] - (unsigned __int8)yy7_result[i_1] - f;
201 result[i_1] = t_2;
202 if ( t_2 < 0 )
203 f = 1;
204 ++i_1;
205 }
206 while ( i_1 < 17 );
207 if ( !f )
208 {
209 index = 0;
210 while ( result[index] == s_xor[index] ) // 这里相当于验证x^2-7*y^2==8
211 {
212 if ( ++index >= 17 )
213 return 1;
214 }
215 }
216 }
217 }
218 return 0;
219 }

到这里思路已经很明确了,16位输入,分成两部分进行异或操作,验证x^2-7*y^2=8

限定条件为

0x100000000000000<x < 0x1000000000000000,(x为8字节,且第8字节<0x10)

0x100000000000000<y<x (y为8字节,)

在进行一步异或即可得到原输入

x^2-7*y^2=8为非标准佩尔方程,求解使用了wolframalpha

https://www.wolframalpha.com/input/?i=x%5E2-7y%5E2%3D8,72057594037927936%3Cx+%3C+1152921504606846976,72057594037927936%3Cy%3Cx

 1 x=385044246406735194
2 y=145533045678356702
3
4 s_xor1=0x646e9881e38c9616
5 s_xor2=0x4f484dbe81dc0884
6
7 t1=hex(x^s_xor1)[2:]
8 t2=hex(y^s_xor2)[2:]
9
10 m1=[]
11 m2=[]
12 for i in range(0,16,2):
13 m1.append(int(t1[i:i+2],16))
14 m2.append(int(t2[i:i+2],16))
15 a=''.join(map(chr,m1))
16 b=''.join(map(chr,m2))
17 print(a[-1::-1]+b[-1::-1])
18 # L3mZ2k9aZ0a36DMM

链接:https://pan.baidu.com/s/1ZpzCus2BdlSujkVRBQZZxQ
提取码:qrlz
复制这段内容后打开百度网盘手机App,操作更方便哦

2019看雪CTF 晋级赛Q2第四题wp的更多相关文章

  1. off-by-one&doublefree. 看雪10月ctf2017 TSRC 第四题赛后学习

    off-by-one 0x00 发现漏洞 1.off-by-one 在massage函数中,如图所示,可以修改的字节数比原内存大小多了一个字节 2.悬挂指针 可以看到,在free堆块的时候,没有清空指 ...

  2. 看雪.TSRC 2017CTF秋季赛第三题

    看雪.TSRC 2017CTF秋季赛第三题 wp 这是一道很简单的题,反调试的坑略多.这道题采用了很多常用的反调试手段,比如调用IsDebuggerPresent.进程名检查等等.另外也有利用SEH的 ...

  3. 看雪CTF第十题

    __int64 sub_140006F50() { __int64 v0; // r8@1 __int64 v1; // r9@1 signed __int64 len; // rax@1 __int ...

  4. 看雪CTF第八题

    IDA查看Exports有3个TlsCallback 只有TlsCallback_2有用 其中创建6个线程用于代码动态解码smc 只有前三个线程有用 分别对check_part1,check_part ...

  5. 看雪CTF第十四题

    from z3 import * dest=[] s = Solver() data = [, , , , , , , , , , , , , , , , , , , , , , , , , , , ...

  6. 看雪CTF第十五题

    1.直接运行起来,再用OD附加 在此处luajit加载并调用main函数 004021C7 E8 64FE0000 call CrackMe. ; luaL_newstate 004021CC 8BF ...

  7. 2019牛客多校赛第一场 补题 I题

    I题  Points Division 题意: 给你n个点,每个点有坐标(xi,yi)和属性(ai,bi),将点集划分为两个集合, 任意 A 集合的点 i 和 B 集合点 j, 不允许 xi > ...

  8. 发现环——第八届蓝桥杯C语言B组(国赛)第四题

    原创 标题:发现环 小明的实验室有N台电脑,编号1~N.原本这N台电脑之间有N-1条数据链接相连,恰好构成一个树形网络.在树形网络上,任意两台 电脑之间有唯一的路径相连. 不过在最近一次维护网络时,管 ...

  9. 『2019/4/9 TGDay2模拟赛 反思与总结』

    2019/4/9 TGDay2模拟赛 今天是\(TG\)模拟赛的第二天了,试题难度也是相应地增加了一些,老师也说过,这就是提高组的难度了.刚开始学难的内容,一道正解也没想出来,不过基本的思路也都是对了 ...

随机推荐

  1. 指纹采集器Live 20R

    最近有个项目需要使用指纹采集器Live 20R,买来这个小玩意后不知道怎么用,看了一些教程和自己摸索了一下,才初步掌握了用的方法. 环境: 硬件:联想 小新 操作系统:Win 10 IDE:VS201 ...

  2. set CSS style in js solutions All In One

    set CSS style in js solutions All In One css in js set each style property separately See the Pen se ...

  3. nasm astrncat_s函数 x86

    xxx.asm: %define p1 ebp+8 %define p2 ebp+12 %define p3 ebp+16 %define p4 ebp+20 section .text global ...

  4. nodejs 创建tcp/udp服务器和客户端

    TCP server // https://nodejs.org/api/net.html const net = require("net"); // https://nodej ...

  5. pycharm + git+gitlab的可视化界面操作

    前言: 写这篇博​​客,主要为了记录一套经过本人实践,并运行通过的操作gitlab流程. 通过以下步骤,可实现最基本的远程服务器(gitlab)和本地工具(pycharm)的,针对两端文件增删改查的及 ...

  6. python 相对路径和绝对路径的区别

    一,Python中获得当前目录和上级目录 获取当前文件的路径: from os import path d = path.dirname(__file__) #返回当前文件所在的目录 # __file ...

  7. socket通信框架——boost asio

    boost asio是一个封装了基本socket的跨平台通信框架.它支持异步访问,并支持tcp的自动封闭控制等操作. 一个简单的通信协议可以为: header body body长 数据 通过boos ...

  8. 翻译:《实用的Python编程》02_02_Containers

    目录 | 上一节 (2.1 数据类型) | 下一节 (2.3 格式化) 2.2 容器 本节讨论列表(list),字典(dict)和集合(set). 概述 通常,程序必须处理许多对象. 股票的投资组合 ...

  9. 在 2021 年你需要掌握的 7 种关于 JavaScript 的数组方法

    在新的一年我们学习这些有用的方法 JavaScript 为我们提供了许多处理数组的不同方法.我们将在几分钟内为您介绍 7 个基本且常用的数据方法,以提高您的 JS 开发技能. 1. Array.map ...

  10. TERSUS无代码开发(笔记03)-常用快捷键

    常用快捷键 1.a 普通行为元件调用 2.b 判断输入的值是什么值 3.c 有条件的传值处理 4.e 输出元件 5.f 传值或流程 6.t 输入元件 7.p 调用元件查询 8.x 判断是否有输入值 图 ...