-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
368 lines (171 loc) · 180 KB
/
atom.xml
File metadata and controls
368 lines (171 loc) · 180 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Hexo</title>
<link href="http://example.com/atom.xml" rel="self"/>
<link href="http://example.com/"/>
<updated>2022-05-11T08:59:18.305Z</updated>
<id>http://example.com/</id>
<author>
<name>John Doe</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>Unicorn简易使用</title>
<link href="http://example.com/2022/05/11/post%E3%80%8AUnicorn%E7%AE%80%E6%98%93%E4%BD%BF%E7%94%A8%E3%80%8B/"/>
<id>http://example.com/2022/05/11/post%E3%80%8AUnicorn%E7%AE%80%E6%98%93%E4%BD%BF%E7%94%A8%E3%80%8B/</id>
<published>2022-05-11T08:27:19.000Z</published>
<updated>2022-05-11T08:59:18.305Z</updated>
<content type="html"><![CDATA[<p>notion链接:<a href="https://massive-delphinium-20c.notion.site/Unicorn-e96707bc165846eda26ff6b2af8df636">https://massive-delphinium-20c.notion.site/Unicorn-e96707bc165846eda26ff6b2af8df636</a></p><p>参考:<a href="https://bbs.pediy.com/thread-253868.htm">https://bbs.pediy.com/thread-253868.htm</a></p>]]></content>
<summary type="html"><p>notion链接:<a href="https://massive-delphinium-20c.notion.site/Unicorn-e96707bc165846eda26ff6b2af8df636">https://massive-delphinium-20c.not</summary>
<category term="tea模拟执行&unicorn" scheme="http://example.com/tags/tea%E6%A8%A1%E6%8B%9F%E6%89%A7%E8%A1%8C-unicorn/"/>
</entry>
<entry>
<title>Unity3D + Frida + Hook</title>
<link href="http://example.com/2022/03/04/Unity3D-Frida-Hook/"/>
<id>http://example.com/2022/03/04/Unity3D-Frida-Hook/</id>
<published>2022-03-04T06:50:54.000Z</published>
<updated>2022-04-07T12:48:00.784Z</updated>
<content type="html"><![CDATA[<h1 id="Unity3D-Frida-Hook"><a href="#Unity3D-Frida-Hook" class="headerlink" title="Unity3D + Frida +Hook"></a>Unity3D + Frida +Hook</h1><p>首先,unity3d是一款游戏引擎,主要开发语言是c#</p><p>unity3d编译后代码文件有两种运行模式:</p><p>1.c#字节码模式,代码位于Assembly-CSharp.dll直接用dnspy反编译</p><p>2.AOT预编译模式,<a href="http://代码位于il2cpp.so/">代码位于il2cpp.so</a></p><p>这里我们主要来研究il2cpp.so的逆向,该文件是一个可执行文件,其代码是游戏的C#字节码编译成的原生汇编代码。AOT编译主要是为了优化性能,但同时也增加了逆向难度。</p><p>il2cpp机制将C#中所有的类型信息保存到global-metadata.dat的文件,通过解析global-metadata文件,可以获得C#代码中的类型、方法、字段等等信息。</p><h2 id="il2cppdumper的使用"><a href="#il2cppdumper的使用" class="headerlink" title="il2cppdumper的使用"></a>il2cppdumper的使用</h2><h3 id="1-安装"><a href="#1-安装" class="headerlink" title="1. 安装"></a>1. 安装</h3><p>我们可以使用il2cppdumper来获取这些信息,这是一个开源工具,可以在github上下载</p><p><a href="https://github.com/Perfare/Il2CppDumper">https://github.com/Perfare/Il2CppDumper</a></p><p>点击右侧releases下面的版本下载即可</p><p>il2cppdumper-vxxx.zip</p><h2 id="2-获取libil2cpp-so和global-metadata-dat"><a href="#2-获取libil2cpp-so和global-metadata-dat" class="headerlink" title="2.获取libil2cpp.so和global -metadata.dat"></a>2.获取libil2cpp.so和global -metadata.dat</h2><p>将你要逆向的apk(xxx.apk)改为(xxx.zip),解压进入目录,拿到libil2cpp.so与global-metadata.dat,目录为</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">\\lib\\armeabi-v7a\\libil2cpp.so</span><br><span class="line">\\assets\\bin\\Data\\Managed\\Metadata\\global-metadata.dat</span><br></pre></td></tr></table></figure><h3 id="执行Il2CppDumper-exe"><a href="#执行Il2CppDumper-exe" class="headerlink" title="*执行Il2CppDumper.exe*"></a><em><strong>*执行Il2CppDumper.exe*</strong></em></h3><p>1.回到<code>Il2CppDumper.exe</code>所在的目录,创建<code>input</code>目录和<code>output</code>目录。</p><p>2.将<code>libil2cpp.so</code>与<code>global-metadata.dat</code>拷贝到<code>input</code>目录中。</p><p>3.创建一个<code>il2cpp_decompilation.bat</code>文件。</p><p><img src="Unity3D-Frida-Hook.assets/image-20220407204800636.png" alt="image-20220407204800636"></p><p><code>il2cpp_decompilation.bat</code>文件内容如下:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">..\\Il2CppDumper.exe libil2cpp.so global-metadata.dat ..\\output</span><br></pre></td></tr></table></figure><p>双击执行<code>il2cpp_decompilation.bat</code> 页面会弹出一个cmd窗口然后显示一些done就是成功了</p><p>4.进入output目录可以看到生成了相关的cs文件和il2cpp.h文件</p><p><img src="Unity3D-Frida-Hook.assets/image-20220407204745752.png" alt="image-20220407204745752"></p><h3 id="查看反编译后的文件"><a href="#查看反编译后的文件" class="headerlink" title="查看反编译后的文件"></a>查看反编译后的文件</h3><p>1.dump.cs</p><p>这个文件会把<code>C#</code>的<code>dll</code>代码的类、方法、字段列出来。</p><p><img src="Unity3D-Frida-Hook.assets/image-20220407204733890.png" alt="image-20220407204733890"></p><p>2.il2cpp.h</p><p>生成的<code>cpp</code>的头文件,从头文件里我们也可以看到相关的数据结构。</p><p>参考:<a href="https://blog.csdn.net/linxinfa/article/details/116572369">https://blog.csdn.net/linxinfa/article/details/116572369</a></p><h2 id="导出修复il2cpp-so符号的脚本"><a href="#导出修复il2cpp-so符号的脚本" class="headerlink" title="导出修复il2cpp.so符号的脚本"></a>导出修复il2cpp.so符号的脚本</h2><p>Il2CppDumper生成的文件中,其中有一个script.py脚本,在IDA中File-Script file选择script.py运行即可,会重命名methodName,添加stringLiteral注释和MakeFunction。</p><p>但是使用il2cppdumper中并没有生成script.py的脚本,经过查找资料和推测,是使用ida.py来调用script.json</p><p>所以恢复符号的步骤是:</p><p>打开 IDA 中的 <strong>File</strong>- <strong>Script file</strong>,依次选择 Il2CppDumper 安装目录下的 ida_with_struct_py3.py ,和使用命令导出的 <code>script.json</code>文件,再选择il2cpp.h。</p><p>恢复符号后部分函数会变成这样</p><p><img src="Unity3D-Frida-Hook.assets/image-20220407204720853.png" alt="image-20220407204720853"></p><h2 id="frida使用"><a href="#frida使用" class="headerlink" title="frida使用"></a>frida使用</h2><p>frida是一款基于python + javascript 的hook框架可运行在android、ios、linux、windows等平台 主要使用动态二进制插桩技术。</p><p>●动态二进制插桩[Dynamic Binary Instrumentation(DBI)]:在程序运行时实时地插入额外代码和数据,对可执行文件没有任何永久改变。</p><p>你能用DBI做些什么呢 (1)访问进程的内存 (2)在应用程序运行时覆盖一些功能 (3)从导入的类中调用函数 (4)在堆上查找对象实例并使用这些对象实例 (5)Hook,跟踪和拦截函数等等</p><p>frida框架分为两部分:</p><ol><li>一部分是运行在系统上的交互工具frida CLI。</li><li>另一部分是运行在目标机器上的代码注入工具 frida-serve。</li></ol><p>一、Window 安装</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">pip install frida</span><br><span class="line">pip install frida-tools</span><br></pre></td></tr></table></figure><p>二、安卓安装adb 连接后输入以下命令查看CPU型号getprop ro.product.cpu.abi</p><p>然后去<a href="https://github.com/frida/frida/releases%E4%B8%AD%E4%B8%8B%E8%BD%BD%E5%AF%B9%E5%BA%94%E5%9E%8B%E5%8F%B7%E4%B8%94%E4%B8%8E%E7%94%B5%E8%84%91%E5%AE%89%E8%A3%85Frida%E7%89%88%E6%9C%AC%E4%B8%80%E8%87%B4%E7%9A%84Frida-server%E7%89%88%E6%9C%AC%E3%80%82%E8%BF%99%E9%87%8C%E6%88%91%E4%B8%8B%E8%BD%BD%E7%9A%84%E6%98%AF">https://github.com/frida/frida/releases中下载对应型号且与电脑安装Frida版本一致的Frida-server版本。这里我下载的是</a> frida-server-12.10.4-android-arm64.xz</p><p>下载完成后将其解压出来,然后重命名为frida-server然后通过adb将其上传到手机adb push .\frida-server /data/local/tmp然后再给其授予777权限。然后在chmod 777 frida-server</p><p>转发端口27042</p><p>至此,我们在安卓端安装完成。接下来,我们检验是否安装成功,在手机端启动./frida-server然后我们在window上执行Frida-ps -U如下图所示,则表示安装成功</p><p>查看进程名:</p><p>firda-ps -U</p><h3 id="frida插件"><a href="#frida插件" class="headerlink" title="frida插件"></a>frida插件</h3><p>idafirida插件能够批量生成hook脚本,在文件当前目录下。</p><p>选中一部分函数,然后使用该插件。</p><p><img src="Unity3D-Frida-Hook.assets/image-20220407204652223.png" alt="image-20220407204652223"></p><p><a href="https://github.com/P4nda0s/IDAFrida">https://github.com/P4nda0s/IDAFrida</a></p><p>使用脚本得到的hook函数是这样的</p><p><img src="Unity3D-Frida-Hook.assets/image-20220407204642947.png" alt="image-20220407204642947"></p><h3 id="hook脚本"><a href="#hook脚本" class="headerlink" title="hook脚本"></a>hook脚本</h3><p>用python封装的hook脚本能重启</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> os <span class="keyword">import</span> device_encoding</span><br><span class="line"><span class="keyword">from</span> ssl <span class="keyword">import</span> SSLSession</span><br><span class="line"><span class="keyword">import</span> frida</span><br><span class="line"><span class="keyword">import</span> sys </span><br><span class="line">device = frida.get_usb_device()</span><br><span class="line">pid = device.spawn([<span class="string">"com.dreamgames.royalmatch"</span>]) <span class="comment">#包名</span></span><br><span class="line">device.resume(pid)</span><br><span class="line">session = device.attach(pid)</span><br><span class="line">script = session.create_script(<span class="string">"""</span></span><br><span class="line"><span class="string"> var str_name_so = "libil2cpp.so"; //要hook的so名</span></span><br><span class="line"><span class="string"> var n_addr_func_offset = 0x000000; //要hook的函数在函数里面的偏移</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> //加载到内存后 函数地址 = so地址 + 函数偏移</span></span><br><span class="line"><span class="string"> var n_addr_so = Module.findBaseAddress(str_name_so);</span></span><br><span class="line"><span class="string"> var n_addr_func = parseInt(n_addr_so, 16) + n_addr_func_offset;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> var ptr_func = new NativePointer(n_addr_func);</span></span><br><span class="line"><span class="string"> Interceptor.attach(ptr_func, </span></span><br><span class="line"><span class="string"> {</span></span><br><span class="line"><span class="string"> onEnter: function(args) </span></span><br><span class="line"><span class="string"> {</span></span><br><span class="line"><span class="string"> console.log("hook on enter no exp");</span></span><br><span class="line"><span class="string"> },</span></span><br><span class="line"><span class="string"> onLeave:function(retval)</span></span><br><span class="line"><span class="string"> {</span></span><br><span class="line"><span class="string"> console.log("hook on Leave no exp");</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string">});</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> </span></span><br><span class="line"><span class="string">"""</span>)</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">on_message</span>(<span class="params">message,data</span>):</span> <span class="comment">#js中执行send函数后要回调的函数</span></span><br><span class="line"> <span class="built_in">print</span>(message)</span><br><span class="line"></span><br><span class="line">script.on(<span class="string">'message'</span>,on_message)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"1234"</span>)</span><br><span class="line">script.load()</span><br><span class="line">sys.stdin.read()</span><br><span class="line"><span class="comment">#打印栈调用</span></span><br><span class="line">console.log(Thread.backtrace(this.context, Backtracer.FUZZY).<span class="built_in">map</span>(DebugSymbol.fromAddress).join(<span class="string">'\\\\n'</span>)</span><br><span class="line"><span class="comment">#打印内存</span></span><br><span class="line">function print_dump(addr,size){</span><br><span class="line"> var buf = Memory.readByteArray(addr,size)</span><br><span class="line"> console.log(<span class="string">"[function] send[*] "</span> + addr.toString() + <span class="string">" "</span>+ <span class="string">"length: "</span> + size.toString() + <span class="string">"\\\\n[data]"</span>)</span><br><span class="line"> console.log(hexdump(buf, {</span><br><span class="line"> offset: <span class="number">0</span>,</span><br><span class="line"> length: size,</span><br><span class="line"> header: false,</span><br><span class="line"> ansi: false</span><br><span class="line"> }));</span><br><span class="line"> console.log(<span class="string">""</span>)</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>这里注意函数的参数FUZZY,一般的搜到的调用都是使用Backtracer.ACCURATE,也是默认参数。但这里打印的不完全,所以还是使用FUZZY比较好。</p><p>打印调用栈的显示的地址是call和ret的地址,而不是函数的地址。</p><p><img src="Unity3D-Frida-Hook.assets/image-20220407204626677.png" alt="image-20220407204626677"></p><p>这也是另一种hook脚本</p><h2 id="hook代码写法"><a href="#hook代码写法" class="headerlink" title="hook代码写法"></a>hook代码写法</h2><p><a href="https://blog.csdn.net/cyjmosthandsome/article/details/120906998">https://blog.csdn.net/cyjmosthandsome/article/details/120906998</a></p><p>关于hook代码的写法就放个链接学习,修改return值什么的。</p><h2 id="frida端口设置和详细使用"><a href="#frida端口设置和详细使用" class="headerlink" title="frida端口设置和详细使用"></a>frida端口设置和详细使用</h2><p><a href="https://q0o0p.top/2021/03/23/hook-frida/">https://q0o0p.top/2021/03/23/hook-frida/</a></p><p>这个博客概括的很全面,转发端口什么都很齐</p>]]></content>
<summary type="html"><h1 id="Unity3D-Frida-Hook"><a href="#Unity3D-Frida-Hook" class="headerlink" title="Unity3D + Frida +Hook"></a>Unity3D + Frida +Hook</h1><p></summary>
<category term="frida hook" scheme="http://example.com/tags/frida-hook/"/>
</entry>
<entry>
<title>演练和使用自己的动态链接库C++</title>
<link href="http://example.com/2022/02/18/DLL/"/>
<id>http://example.com/2022/02/18/DLL/</id>
<published>2022-02-18T12:36:30.000Z</published>
<updated>2022-02-19T07:40:30.640Z</updated>
<content type="html"><![CDATA[<p>原文链接<a href="https://docs.microsoft.com/zh-cn/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=msvc-170">https://docs.microsoft.com/zh-cn/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=msvc-170</a></p><h1 id="演练和使用自己的动态链接库C"><a href="#演练和使用自己的动态链接库C" class="headerlink" title="演练和使用自己的动态链接库C++"></a>演练和使用自己的动态链接库C++</h1><p>1.在visual studio中创建DLL项目。</p><p>2.将导出的函数和变量添加到该DLL。</p><p>3.在Visual Studio 中创建一个控制台应用项目。</p><p>4.在该控制台应用中使用从DLL导入的函数和变量。</p><p>5.运行已完成的应用。</p><p>本演练中两个方案,一个生成 DLL,另一个生成客户端应用。 DLL 使用 C 调用约定。 只要平台、调用约定和链接约定匹配,便可从采用其他编程语言编写的应用中进行调用。 客户端应用使用隐式链接 ,其中 Windows 在加载时将应用链接到 DLL。 此链接允许应用调用 DLL 提供的函数,就像调用静态链接库中的函数一样。</p><h2 id="创建DLL项目"><a href="#创建DLL项目" class="headerlink" title="创建DLL项目"></a>创建DLL项目</h2><p>新建一个MathLibrary.dll项目,可以搜索dll来创建,我这里的版本是visual studio 2022</p><img src="/2022/02/18/DLL/dll-2.png" class="" title="dll-2"><p>创建以后就可以在解决方案资源管理器中看到生成的项目和源文件了</p><img src="/2022/02/18/DLL/dll-1.png" class="" title="dll-1"><p>接下来我们需要创建一个头文件来声明DLL导出的函数,然后将函数定义添加到DLL,使之具备功能。</p><h3 id="1-将头文件添加到DLL"><a href="#1-将头文件添加到DLL" class="headerlink" title="1.将头文件添加到DLL"></a>1.将头文件添加到DLL</h3><p>1.在菜单栏中选择项目-添加新项</p><p>2.左侧选择Visual C++。选择头文件(.h)。指定MathLibrary.h作为头文件的名称。生成文件。</p><p>这里的实例是斐波那契递归</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> MATHLIBRARY_EXPORTS</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> MATHLIBRARY_API __declspec(dllexport)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> MATHLIBRARY_API __declspec(dllimport)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">//初始化一个序列</span></span><br><span class="line"><span class="keyword">extern</span> <span class="string">"C"</span> <span class="function">MATHLIBRARY_API <span class="keyword">void</span> <span class="title">fibonacci_init</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function"><span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">long</span> a, <span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">long</span> b)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//生成序列中下一个值</span></span><br><span class="line"><span class="comment">//成功返回true,并更新当前值和索引,溢出时为false,保持当前值和索引不变</span></span><br><span class="line"><span class="keyword">extern</span> <span class="string">"C"</span> <span class="function">MATHLIBRARY_API <span class="keyword">bool</span> <span class="title">fibonacci_next</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//获取系列中的当前值</span></span><br><span class="line"><span class="keyword">extern</span> <span class="string">"C"</span> <span class="function">MATHLIBRARY_API <span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">long</span> <span class="title">fibonacci_current</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//获取当前值在序列中的位置</span></span><br><span class="line"><span class="keyword">extern</span> <span class="string">"C"</span> <span class="function">MATHLIBRARY_API <span class="keyword">unsigned</span> <span class="title">fibonacci_index</span><span class="params">()</span></span>;</span><br></pre></td></tr></table></figure><p>头文件中声明一些函数以生成通用的斐波那契序列,给定了两个初始值。</p><h3 id="2-向DLL添加实现"><a href="#2-向DLL添加实现" class="headerlink" title="2.向DLL添加实现"></a>2.向DLL添加实现</h3><p>1.在解决方案资源管理器中右键点击源文件-添加-新项,创建名为MathLibrary.cpp的新.cpp文件。</p><p>编辑该文件</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"pch.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><utility></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><limits.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"MathLibrary.h"</span><span class="comment">//为dll定义导出的函数</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">//dll内部状态变量</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">long</span> previous_; <span class="comment">//之前的值(如果有)</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">long</span> current_; <span class="comment">//当前序列值</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">unsigned</span> index_; <span class="comment">//当前位置</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//初始化一个序列,这个函数必须在任何其他函数之前调用</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">fibonacci_init</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function"><span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">long</span> a,</span></span></span><br><span class="line"><span class="params"><span class="function"><span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">long</span> b)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">index_ = <span class="number">0</span>;</span><br><span class="line">current_ = a;</span><br><span class="line">previous_ = b; <span class="comment">//初始化特殊情况</span></span><br><span class="line">}</span><br><span class="line"><span class="comment">//生成序列中的下一个值,成功返回true,错误返回false</span></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">fibonacci_next</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">//检查是否溢出结果或位置</span></span><br><span class="line"><span class="keyword">if</span> ((ULLONG_MAX - previous_ < current_) ||</span><br><span class="line">(UINT_MAX == index_))</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="comment">//特殊情况当序列位置为0,只要返回b的值</span></span><br><span class="line"><span class="keyword">if</span> (index_ > <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line"><span class="comment">//否则,计算下一个序列值</span></span><br><span class="line">previous_ += current_;</span><br><span class="line">}</span><br><span class="line">std::<span class="built_in">swap</span>(current_, previous_);</span><br><span class="line">++index_;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//得到序列中的当前值</span></span><br><span class="line"><span class="function"><span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">long</span> <span class="title">fibonacci_current</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">return</span> current_;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//得到当前值在序列中的位置</span></span><br><span class="line"><span class="function"><span class="keyword">unsigned</span> <span class="title">fibonacci_index</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">return</span> index_;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>到这里dll文件就编写完毕了,可以通过点击菜单栏中生成-生成解决方案来查看是否有错误。</p><p>这样就成功使用visual studio创建了一个dll。</p><h2 id="创建可使用DLL客户端应用"><a href="#创建可使用DLL客户端应用" class="headerlink" title="创建可使用DLL客户端应用"></a>创建可使用DLL客户端应用</h2><p>使用visual studio新建一个控制台应用,将项目名称设置为MathClient。(不需要选中将解决方案和项目放在同意目录中)</p><p>在源代码中调用MathLibrary函数,项目中必须包括MathLibrary.h文件,将头文件复制到客户端应用项目中,然后将其作为现有项添加到项目中。</p><p>在你的默认目录下去找到MathLibrary.h的文件和framework.h的文件复制到MathClient/MathClient的目录下,再去MathLibrary的x64/debug目录下去找到.dll文件和.lib文件,一个是动态链接库,一个是静态链接库,同样复制到MathClient/MathClient的目录下。</p><p>完成上述以后,右击解决方案资源管理器中的MathClient,属性-常规-包含目录,添加MathClient/MathClient,这样就可以使用.dll库和头文件了。</p><p>然后在MathClient.cpp文件中写入以下代码:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Mathclient.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"MathLibrary.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"pch.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> comment(lib, <span class="meta-string">"MathLibrary.lib"</span>) <span class="comment">//需要加!!!!!(底下有不加的报错阐述)</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="comment">//初始化一个斐波那契数列</span></span><br><span class="line"><span class="built_in">fibonacci_init</span>(<span class="number">1</span>, <span class="number">1</span>);</span><br><span class="line"><span class="comment">//写出序列值知道溢出</span></span><br><span class="line"><span class="keyword">do</span> {</span><br><span class="line">std::cout << <span class="built_in">fibonacci_index</span>() << <span class="string">": "</span></span><br><span class="line"><< <span class="built_in">fibonacci_current</span>() << std::endl;</span><br><span class="line">} <span class="keyword">while</span> (<span class="built_in">fibonacci_next</span>());</span><br><span class="line"><span class="comment">//报告溢出前写入的值的计数</span></span><br><span class="line">std::cout << <span class="built_in">fibonacci_index</span>() << <span class="string">": "</span></span><br><span class="line"><< <span class="built_in">fibonacci_index</span>() + <span class="number">1</span> <<</span><br><span class="line"><span class="string">" Fibonacci sequence values fit in an "</span> <<</span><br><span class="line"><span class="string">"unsigned 64-bit integer."</span> << std::endl;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>如果头文件上的include没有下划报错什么的就是包含目录路径设置好了)</p><h3 id="设置依赖和附加库目录"><a href="#设置依赖和附加库目录" class="headerlink" title="设置依赖和附加库目录"></a>设置依赖和附加库目录</h3><p>项目-属性-链接器,右侧框中有一个附加依赖项,输入MathLibrary.lib,添加依赖</p><p>项目-属性-链接器-常规, 右侧框中附加库目录,定位到dll文件的库中。</p><h2 id="报错提醒)"><a href="#报错提醒)" class="headerlink" title="报错提醒)"></a>报错提醒)</h2><p>折腾这个dll的链接其实还挺麻烦的,一开始怎么也弄不对,重新写了很多遍。最后卡在link2019的一个报错上。它提示我main函数中找不到__imp_xxxx(函数)。</p><p>这里我先使用dumpbin工具查看dll导出符号,因为是cpp文件,所以有符号被修饰的可能性,导出符号的方法看<a href="https://blog.csdn.net/zsc_976529378/article/details/105834611">https://blog.csdn.net/zsc_976529378/article/details/105834611</a></p><p>因为我找到的dumpbin.exe不对劲,所以我是用第二种方法的,但找不到命令提示所以可以自己搭建一个。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">从菜单选择“Tools”,然后选择“外部工具”。输入如下:</span><br><span class="line"></span><br><span class="line">标题:Visual Studio 命令提示(&C)</span><br><span class="line">命令:%systemroot%\system32\cmd.exe</span><br><span class="line">参数:/K "vsdevcmd.bat -no_logo"</span><br><span class="line">初始目录:D:\Program Files (x86)\Microsoft Visual Studio\2022\Community\Common7\Tools</span><br><span class="line">注意:初始化目录为你安装vs的目录中找</span><br><span class="line"></span><br><span class="line">然后点击【应用】,【确认】即可</span><br></pre></td></tr></table></figure><p>然后就可以在菜单-工具中找到命令提示了)</p><p>查看dll导出符号没有被改,就转眼到了这个</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">__imp_xxxx</span><br></pre></td></tr></table></figure><p>是个什么东西,经过google后发现需要将lib文件添加到代码工程中</p><p>原文链接:<a href="https://blog.csdn.net/HideInTime/article/details/103181629">https://blog.csdn.net/HideInTime/article/details/103181629</a></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">出现字符_imp,说明不是真正的静态库,而是某个动态库的导入库,导入函数和自己不同名,所以加了字符_imp。比如说_imp_GetUserNameA就是GetUserNameA函数。</span><br><span class="line"></span><br><span class="line">会报这种错误的原因:</span><br><span class="line"></span><br><span class="line">1、说明注册表函数没有相关的lib库,我们需要在MSDN下搜索函数。</span><br><span class="line"></span><br><span class="line">2、如果有引入三方库文件,可能存在库编译时和自己的项目编译时的运行库选择不一致(MT/MTd/MD/MDd)。</span><br></pre></td></tr></table></figure><p>于是在控制台文件main函数开头加入一行</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">pragma</span> comment(lib, <span class="meta-string">"MathLibrary.lib"</span>)</span></span><br></pre></td></tr></table></figure><p>就可以成功运行了!</p>]]></content>
<summary type="html"><p>原文链接<a href="https://docs.microsoft.com/zh-cn/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=msvc-170">https://</summary>
<category term="DLL" scheme="http://example.com/tags/DLL/"/>
</entry>
<entry>
<title>csapp-8</title>
<link href="http://example.com/2022/02/16/csapp-8/"/>
<id>http://example.com/2022/02/16/csapp-8/</id>
<published>2022-02-16T08:54:57.000Z</published>
<updated>2022-02-17T14:13:08.187Z</updated>
<content type="html"><![CDATA[<h1 id="第8章"><a href="#第8章" class="headerlink" title="第8章"></a>第8章</h1><h2 id="进程"><a href="#进程" class="headerlink" title="进程"></a>进程</h2><p>异常是允许操作系统提供进程概念的基本构造块</p><p>在前面的章节也有提到过进程,这是一个抽象的概念,在运行程序是我们会得到一个假象就好像我们的程序是系统中运行的唯一的程序一样。这些假象都是通过进程的概念提供给我们的。</p><p>进程的定义就是一个执行中程序的实例。系统中每个程序都运行在某个进程的上下文中,而上下文是有程序正确运行所需的状态组成的。</p><p>每次用户向shell输入可执行文件的名字运行程序时shell就会创建一个新的进程,然后在上下文中运行这个可执行目标文件。</p><p>进程提供给应用程序的关键抽象由两个部分组成。</p><p>1.一个独立的逻辑控制流,构造了程序独占使用处理器的假象</p><p>2.一个私有的地址空间,构造了程序独占使用内存系统的假象</p><h3 id="逻辑控制流"><a href="#逻辑控制流" class="headerlink" title="逻辑控制流"></a>逻辑控制流</h3><p>当一个系统运行三个进程时,处理器的一个物理控制流被分成了三个逻辑流,每个进程一个,三个逻辑流可以交错也可以分开。</p><p>执行的关键点在于进程是轮流使用处理器的,每个进程执行它的流的一部分,然后被抢占(暂时挂起)然后轮到其他进程,看起来就像都在独占的使用处理器,实际上处理器会有周期性的停顿,但并不改变程序内存位置或寄存器的内容。</p><h3 id="并发流"><a href="#并发流" class="headerlink" title="并发流"></a>并发流</h3><p>前面也提到过并发,在这里有详细的讲。</p><p>一个逻辑流的执行时间上与另一个流重叠,称为并发流,这两个流被称为并发的运行。互相并发。</p><p><strong>多个流并发的执行</strong>的一般现象称为<strong>并发</strong>,<strong>一个进程和其他进程轮流运行</strong>的概念称为<strong>多任务</strong>。一个进程执行它的控制流的一部分的每一段时间叫做时间片。因此多任务也叫时间分片。</p><p>如果两个流并发地运行在不同的处理器核或者计算机上,那么称他们为<strong>并行流</strong>。</p><img src="/2022/02/16/csapp-8/3.1-16450017385201.png" class="" title="3.1"><h3 id="私有地址空间"><a href="#私有地址空间" class="headerlink" title="私有地址空间"></a>私有地址空间</h3><p>在一台n位地址的机器上,地址空间是2的n次方个可能地址的集合。进程为每个程序提供自己的私有的地址空间。一般而言,和这个空间中某个地址相关联的内存字节是不能被其他进程读或者写的。</p><p>每个这样的空间都有相同的通用结构</p><p>地址空间底部是保留给用户程序的,通常包括代码、数据、和堆栈段。代码段总是从地址0x400000开始。地址空间顶部保留给内核。地址空间的这个部分包含内核在代表进程执行指令时使用的代码,数据和栈。</p><img src="/2022/02/16/csapp-8/3-2-16450134966762.png" class="" title="3-2"><h3 id="用户模式和内核模式"><a href="#用户模式和内核模式" class="headerlink" title="用户模式和内核模式"></a>用户模式和内核模式</h3><p>处理器通常是用某个控制寄存器的一个模式位来提供这种功能的,该寄存器描述了进程当前享有的特权。当设置了模式位时,进程就运行在内核模式中。一个运行在内核模式的进程可以执行指令集中的任何指令,并且可以访问系统中的任何内存位置。</p><p>而没有设置模式位时,进程就运行在用户模式中,无法执行特权指令。(比如停止处理器等)</p><p>运行程序时一开始一般是在用户模式中的,当中断,故障或者陷入系统调用这样的异常时,处理器将模式从用户模式变为内核模式,当返回应用程序代码时,处理器就把模式改回用户模式。</p><p>linux中可以使用/proc文件系统,它允许用户模式进程访问内核数据结构的内容。</p><h3 id="上下文切换"><a href="#上下文切换" class="headerlink" title="上下文切换"></a>上下文切换</h3><p>操作系统内核使用上下文切换的异常控制流来实现多任务。即实现上面提到的挂起程序和抢占等。</p><p>内核为每个进程维持一个上下文,它由一些对象的值组成,这些对象包括寄存器和栈,内核数据结构等等。在程序执行时,内核可以决定抢占进程,并重新开始先前被抢占的进程,被称为调度。这时候即进行了上下文切换。</p><p>1)保存当前进程的上下文 2)恢复先前被抢占的进程的上下文 3)将控制传递给这个新恢复的进程</p><img src="/2022/02/16/csapp-8/3-3.png" class="" title="3-3"><h3 id="系统错误处理"><a href="#系统错误处理" class="headerlink" title="系统错误处理"></a>系统错误处理</h3><p>当unix系统级函数遇到错误时,它们通常会返回到-1,并设置全局整数变量errno来表示什么出错了</p><img src="/2022/02/16/csapp-8/3-4.png" class="" title="3-4"><p>但这样表示会让程序很难看,所以我们可以定义错误报告函数,并包装</p><img src="/2022/02/16/csapp-8/3-5.png" class="" title="3-5"><img src="/2022/02/16/csapp-8/3-6.png" class="" title="3-6"><p>于是调用就可以缩减成一行</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pid = Fork();</span><br></pre></td></tr></table></figure><h2 id="进程控制"><a href="#进程控制" class="headerlink" title="进程控制"></a>进程控制</h2><h3 id="获取进程ID"><a href="#获取进程ID" class="headerlink" title="获取进程ID"></a>获取进程ID</h3><p>每个进程都有一个唯一的正数(非零)ID(PID)。gitpid函数返回调用进程的PID。gitppid函数返回它的父进程的PID(创建调用进程的进程)</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">pid_t</span> <span class="title">getpid</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">pid_t</span> <span class="title">getppid</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br></pre></td></tr></table></figure><p>他们分别返回一个类型为pid_t的整数值,在linux系统上它在types.h中被定义为int。</p><h3 id="创建和终止进程"><a href="#创建和终止进程" class="headerlink" title="创建和终止进程"></a>创建和终止进程</h3><p>进程的三种状态</p><p>1.运行(在cpu执行或等待执行且最终被内核调度)</p><p>2.停止(被挂起且不会被调度)</p><p>3.终止(停止了)</p><p>当父进程调用fork函数创建一个新的运行的子进程</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">pid_t</span> <span class="title">fork</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"><span class="comment">//返回,子进程返回0,父进程返回子进程的PID,出错则为-1</span></span><br></pre></td></tr></table></figure><p>新创建的子进程和父进程几乎相同,虚拟地址空间相同(独立副本),且共享文件,它们的不同在于有不同的PID。</p><p>fork函数调用一次却返回两次。一次在调用父进程中,一次在新创建子进程中。这里给出一个示例程序:</p><img src="/2022/02/16/csapp-8/3-7.png" class="" title="3-7"><p>在这里,父进程和子进程是并发执行的,下面是该进程的进程图。</p><img src="/2022/02/16/csapp-8/3-8.png" class="" title="3-8"><h3 id="回收子进程"><a href="#回收子进程" class="headerlink" title="回收子进程"></a>回收子进程</h3><p>当一个进程由于某种原因终止时,进程会被保存在已终止的状态中,直到被父进程回收。当父进程终止时,内核会安排init进程来回收。init进程的PID为1,是系统启动时内核创建的,不会终止。</p><p>进程可以通过waitpid函数来等待子进程终止或者停止。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/wait.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">pid_t</span> <span class="title">waitpid</span><span class="params">(<span class="keyword">pid_t</span> pid, <span class="keyword">int</span> *statusp, <span class="keyword">int</span> options)</span></span>;</span><br><span class="line"><span class="comment">//成功返回子进程PID,WHOHANG则为0,其他错误则为-1。</span></span><br></pre></td></tr></table></figure><p>waitpid挂起调用进程的执行,直到它的等待集合中的一个子进程终止。如果等待集合中有进程刚调用就终止了那waitpid就立即返回,在这两种情况中,waitpid返回导致waitpid返回返回的已终止子进程的PID。</p><p>1.判定等待集合的成员(pid>0,等待集合就是单独的子进程,pid=-1,等待集合就是由父进程和所有子进程组成的)</p><p>2.修改默认行为(通过将options设置为常量的各种组合来修改默认行为)(电子书p552,纸质p517)</p><p>3.检查已回收的子进程的退出状态</p><p>4.错误条件(如果调用进程没有子进程则waitpid返回-1,信号中断也返回-1)</p><p>5.wait(waitpid的简单版本)</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/wait.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">pid_t</span> <span class="title">wait</span><span class="params">(<span class="keyword">int</span> *statusp)</span></span>;</span><br><span class="line"><span class="comment">//等于调用waitpid(-1,&status,0)</span></span><br><span class="line"><span class="comment">//成功返回子进程PID,出错-1</span></span><br></pre></td></tr></table></figure><h3 id="让进程休眠"><a href="#让进程休眠" class="headerlink" title="让进程休眠"></a>让进程休眠</h3><p>sleep函数将进程挂起一段指定的时间。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="title">sleep</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">int</span> secs)</span></span>;</span><br><span class="line"><span class="comment">//返回还要休眠的秒数</span></span><br></pre></td></tr></table></figure><p>请求时间到了slee返回0,若信号中断过早返回则会返回不为0.</p><p>pause函数让调用函数休眠,直到该进程收到一个信号。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">pause</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br></pre></td></tr></table></figure><h3 id="加载并运行程序"><a href="#加载并运行程序" class="headerlink" title="加载并运行程序"></a>加载并运行程序</h3><p>execve函数在当前进程的上下文加载并运行一个新程序。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">execve</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span> *filename, <span class="keyword">const</span> <span class="keyword">char</span> *argv[])</span>,</span></span><br><span class="line"><span class="function"> <span class="keyword">const</span> <span class="keyword">char</span> * envp[])</span>;</span><br><span class="line"><span class="comment">//成功不返回,错误返回-1</span></span><br></pre></td></tr></table></figure><p>execve函数加载并运行可执行目标文件filename</p><h3 id="简单shell示例"><a href="#简单shell示例" class="headerlink" title="简单shell示例"></a>简单shell示例</h3><p>电子书p560,纸质p524</p><h2 id="信号"><a href="#信号" class="headerlink" title="信号"></a>信号</h2><p>在上面的简单shell中是有缺陷的,在于它不回收它的后台子进程。修改这个缺陷就要求使用信号。</p><p>信号是一种更高层的软件形式的异常,称为Linux信号,它允许进程和内核中断其他进程。Linux系统支持30多种不同类型的信号,每种信号类型都对应于某种系统事件。(p563/p527)</p><img src="/2022/02/16/csapp-8/3-9.png" class="" title="3-9"><h3 id="信号术语"><a href="#信号术语" class="headerlink" title="信号术语"></a>信号术语</h3><p>传送信号到目的进程由两个不同步骤组成</p><p>1.发送信号</p><p>内核通过更新目的进程上下文中的某个状态,发送一个信号给目的进程。</p><p>2.接收信号</p><p>当目的进程被内核强迫以某种方式对信号的发送做出反应时就接收了信号。捕获信号通过信号处理程序。</p><img src="/2022/02/16/csapp-8/3-10.png" class="" title="3-10"><p>一个发出而没有被接收的信号叫做待处理信号,任何时刻一种类型至多有一个待处理信号。如果已有一个待处理k类型信号,再有其他k类型的信号都会被简单的丢弃。</p><p>一个待处理信号只能被接收一次</p><h3 id="发送信号"><a href="#发送信号" class="headerlink" title="发送信号"></a>发送信号</h3><h4 id="1-进程组"><a href="#1-进程组" class="headerlink" title="1.进程组"></a>1.进程组</h4><p>发送信号机制基于进程组这个概念。每个进程都只属于一个进程组,进程组是由一个正整数进程组ID来标识的。getpgrp函数返回当前进程的进程组ID</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="function"><span class="keyword">pid_t</span> <span class="title">getpgrp</span><span class="params">(<span class="keyword">void</span>)</span></span>;<span class="comment">//返回进程组ID</span></span><br></pre></td></tr></table></figure><p>默认条件下,一个子进程和父进程同属一个进程组,可以通过setpgid来改变自己或者其他进程的进程组</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">setpgid</span><span class="params">(<span class="keyword">pid_t</span> pid, <span class="keyword">pid_t</span> pgid)</span> <span class="comment">//成功返回0,错误返回-1</span></span></span><br></pre></td></tr></table></figure><p>setpgid函数将进程pid的进程组改为pgid。如果pid为0,那么就使用当前进程的PID。如果pgid是0,那么就用pid指定的进程的PID作为进程组的ID。</p><h4 id="2-用-bin-kill-程序发送信号"><a href="#2-用-bin-kill-程序发送信号" class="headerlink" title="2.用/bin/kill 程序发送信号"></a>2.用/bin/kill 程序发送信号</h4><p>/bin/kill程序可以向另外的进程发送任意的信号。</p><h4 id="3-从键盘发送信号"><a href="#3-从键盘发送信号" class="headerlink" title="3.从键盘发送信号"></a>3.从键盘发送信号</h4><p>Unix shell使用作业(job)这个抽象概念来表示为对一条命令行求值而创建的进程。在任何时刻,至多只有一个前台作业和0个或多个后台作业。</p><img src="/2022/02/16/csapp-8/3-11.png" class="" title="3-11"><p>默认情况下,输入ctrl+c是终止前台作业,输入ctrl+z是挂起前台作业。</p><h4 id="4-用kill函数发送信号"><a href="#4-用kill函数发送信号" class="headerlink" title="4.用kill函数发送信号"></a>4.用kill函数发送信号</h4><p>进程通过调用kill函数发送信号给其他进程</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><signal.h></span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">kill</span><span class="params">(<span class="keyword">pid_t</span> pid, <span class="keyword">int</span> sig)</span></span>;</span><br><span class="line"><span class="comment">//成功则返回0,错误返回-1</span></span><br></pre></td></tr></table></figure><h4 id="5-用alarm函数发送信号"><a href="#5-用alarm函数发送信号" class="headerlink" title="5.用alarm函数发送信号"></a>5.用alarm函数发送信号</h4><p>进程可以通过调用alarm函数向自己发送信号。</p><h3 id="接收信号"><a href="#接收信号" class="headerlink" title="接收信号"></a>接收信号</h3><p>当内核把进程p从内核模式切换到用户模式时,他会检查进程p的未被阻塞的待处理信号的集合。如果集合为空,内核将控制传递到p的逻辑控制流下一条指令。如果集合为非空,那么内核选择某个信号k,并强制p回收信号k。</p><p>每个信号类型都有一个预定义的默认行为,例如:</p><p>1.进程终止 2.进程终止并转储内存 3.进程(挂起)直到被SIGCONT信号重启 4.进程忽略该信号</p><p>进程可以通过signal函数修改和信号相关联的默认行为。唯一的例外是SIGSTOP和SIGKILL,它们的默认行为是不能修改的。</p><h3 id="阻塞和解除阻塞信号"><a href="#阻塞和解除阻塞信号" class="headerlink" title="阻塞和解除阻塞信号"></a>阻塞和解除阻塞信号</h3><p>Linux提供阻塞信号的隐式和显式的机制:</p><p>隐式:内核默认阻塞任何当前处理程序正在处理信号类型的待处理信号(前面有讲过)</p><p>显式:应用程序可以使用sigprocmask函数和它的辅助函数,明确地阻塞和解除阻塞选定的信号。</p><h3 id="编写信号处理程序"><a href="#编写信号处理程序" class="headerlink" title="编写信号处理程序"></a>编写信号处理程序</h3><p>信号处理是Linux系统编程最棘手的一个问题,有很多原因。例如处理程序和主程序的并发运行,共享同样的全局变量,因此可能与主程序和其他处理程序互相干扰。如何以及何时接收信号的规则比较奇怪。不同系统有不同的信号处理语义等等。</p><h4 id="1-安全的信号处理"><a href="#1-安全的信号处理" class="headerlink" title="1.安全的信号处理"></a>1.安全的信号处理</h4><p><strong>G0</strong>:信号处理要尽可能简单。例如处理程序简单地设置全局标志并立即返回,所有与接收信道相关的处理都由主程序执行,周期性检查重置标志。</p><p><strong>G1</strong>:在处理程序中只调用异步信号安全的函数。他们能被信号处理程序安全地调用。因为它是可重入的(例如只访问局部变量或者不能被信号处理程序中断)。</p><img src="/2022/02/16/csapp-8/3-12.png" class="" title="3-12"><p>信号处理程序中产生输出唯一安全的方法是使用write函数。或者可以开发一些安全的函数(SIO包(安全的I/O包))可以用来在信号处理程序中打印简单的消息。</p><p><strong>G2</strong>:保存和恢复errno。在处理程序中调用errno可能会干扰主程序中其他依赖该函数的部分,可以将errno保存在一个局部变量中,在处理程序返回前恢复它。(只有需要返回时需要)</p><p><strong>G3</strong>:阻塞所有信号,保护对共享全局数据结构的访问。当主程序和处理程序共享全局数据结构且访问该数据结构时应该暂时阻塞所有信号。</p><p><strong>G4</strong>:用volatile声明全局变量。处理程序更新全局变量,main周期性得读变量。对于一个优化编译器来说,main中的变量值看起来从来没有变化过,因此使用缓存在寄存器中的副本来满足对变量的每次引用是很安全的。如果这样main函数可能永远不能看到处理程序更新过的值。</p><p>而用volatile类型限定符来定义一个变量,告诉编译器不要缓存这个变量,它强迫编译器每次引用该变量时要从内存中读取。一般来说和其他共享数据结构一样该暂时阻塞信号以保安全引用。</p><p><strong>G5</strong>:用sig_atomic_t声明标志。在常见的处理程序设计中,处理程序会写全局标志来记录收到了信号。主程序周期性地读这个标志,响应信号,再清除该标志。sig_atomic_t是c提供的一种整形数据类型,对它的读和写是不会中断的,所以可以安全的读写,不需要阻塞信号。但只能用于单个的读写,例如flag++则要多条指令。</p><h4 id="2-正确的信号处理"><a href="#2-正确的信号处理" class="headerlink" title="2.正确的信号处理"></a>2.正确的信号处理</h4><p>不能够简单的假设信号是排队的,信号在处理中最多接收一个相同类型的信号,其他相同类型的信号再来会被简单的丢弃,(前面提到过)并且需要正确的回收所有的僵死程序(已终止但未被回收)。在编写程序中正确的信号处理也需要注意,不然就会导致信号的丢失。</p><h4 id="3-可移植的信号处理"><a href="#3-可移植的信号处理" class="headerlink" title="3.可移植的信号处理"></a>3.可移植的信号处理</h4><p>Unix信号处理另一个缺陷在于不同的系统有不同的信号处理语义。例如:</p><p>1.signal函数语义各有不同</p><p>2.系统调用可以被中断</p><p>为了解决这些问题,posix标准定义了sigaction函数,允许用户在设置信号处理时明确指定他们想要的信号处理语义。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><signal.h></span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">sigaction</span><span class="params">(<span class="keyword">int</span> signum, struct sigaction *act,</span></span></span><br><span class="line"><span class="params"><span class="function"> struct sigaction *oldact)</span></span>;</span><br><span class="line"><span class="comment">//成功则为0,出错则为-1</span></span><br></pre></td></tr></table></figure><p>sigaction函数运用不广泛,因为它要求用户设置一个复杂结构的条目。更简洁的是定义一个包装函数Signal</p><p>Signal包装函数设置了一个信号处理程序,其信号语义如下:</p><p>1.只有这个处理程序当前正在处理的那种类型的信号被阻塞</p><p>2.和所有信号实现一样,信号不会排队等待</p><p>3.只要可能,被中断的系统调用会自动重启</p><p>4.一旦设置了信号处理程序,它就会一直保持,知道Signal带着handler参数被调用</p><h3 id="同步流以避免并发错误"><a href="#同步流以避免并发错误" class="headerlink" title="同步流以避免并发错误"></a>同步流以避免并发错误</h3><p>经典的unix结构,父进程在一个全局作业列表中记录着它的当前子进程,每个作业一个条目。addjob和deletejob函数分别向这个作业列表添加和从中删除作业。</p><p>当父进程创建一个新的子进程时,它就把子进程添加到作业列表中。当父进程在SIGCHLD处理程序中回收一个终止的僵死子进程时,它就从作业列表中删除这个子进程。</p><p>但对于父进程的main程序和信号处理流的某些交错,可能会在addjob之前调用deletejob,这导致作业列表中出现一个不正确的条目,对应于一个不再勋在而且永远也不会被删除的作业,另一方面也有一些交错时间按照正确的顺序发生。</p><p>我们可以通过在调用fork之前,阻塞SIGCHLD信号,然后调用addjob之后取消阻塞这些信号,这样保证了在子程序被添加到作业列表之后回收该子进程。</p><h3 id="显示地等待信号"><a href="#显示地等待信号" class="headerlink" title="显示地等待信号"></a>显示地等待信号</h3><p>有时候主程序需要显式地等待某个信号处理程序运行。例如当创建一个前台作业时,在接受下一条用户命令之前,它必须等待作业终止,被SIGCHLD处理程序回收。</p><p>一个基本思路是父进程设置SIGINT和SIGCHLD的处理程序,然后进入无限循环,阻塞SIGCHLD信号,避免上面讨论的父进程和子进程之间调用的顺序竞争。创建子进程后把pid重置为0,取消阻塞,然后以循环的方式等待pid变为非零。子进程终止后,处理程序回收,把非零PID复制给全局pid变量,会终止循环,父进程继续其他的工作,然后进行下一次迭代。</p><p>当代码正确执行时,循环在浪费处理器资源,我们可以通过在循环中插入sleep,pause,但这样收到一个或多个SIGINT信号时pause会被中断,且会引起竞争:在while测试后和pause之前收到SIGCHLD信号,pause会永远睡眠,sleep又会使代码执行时间过长,合适的解决方法是使用sigsuspend</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><signal.h></span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">sigsuspend</span><span class="params">(<span class="keyword">const</span> <span class="keyword">sigset_t</span> *mask)</span></span>;</span><br><span class="line"><span class="comment">//返回-1</span></span><br></pre></td></tr></table></figure><p>sigsuspend函数暂时用mask替换当前的阻塞集合,然后挂起该进程,直到收到一个信号,其行为要么是运行一个处理程序,要么是终止该进程。如果它的行为是终止,那么该进程不从sigsuspend返回就直接终止。如果是运行一个处理程序,那么sigsuspend从处理程序返回,恢复调用时原有的阻塞集合。</p><h3 id="非本地跳转"><a href="#非本地跳转" class="headerlink" title="非本地跳转"></a>非本地跳转</h3><p>c语言提供了一种用户级的异常控制流形式,称为非本地跳转,它将控制直接从一个函数转移到另一个当前正在执行的函数,而不需要经过正常的调用返回序列,非本地跳转是通过setjmp和longjmp函数来提供的</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><setjmp.h></span></span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">setjmp</span><span class="params">(jmp_buf env)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">sigsetjmp</span><span class="params">(sigjmp_buf env, <span class="keyword">int</span> savesigs)</span></span>;</span><br></pre></td></tr></table></figure><p>非本地跳转的一个重要应用是允许从一个深层嵌套的函数调用中立即返回,通常是由检测到某个错误情况引起的。可以使用非本地跳转直接返回到一个普通的本地化的错误处理程序,而不是费力地解开调用栈。</p><p>非本地跳转的另一个重要应用是使一个信号处理程序分支到一个特殊的代码位置,而不是返回到被信号到达中断了的指令位置。</p><h3 id="操作进程的工具"><a href="#操作进程的工具" class="headerlink" title="操作进程的工具"></a>操作进程的工具</h3><p>linux系统提供了监控和操作进程的有用工具。</p><p>STRACE:打印一个正在运行的程序和它的子进程调用的每个系统调用的轨迹。</p><p>PS:列出当前系统中的进程。</p><p>TOP:打印出关于当前进程资源使用的信息</p><p>PMAP:系那是进程的内存映射。</p><p>/proc:虚拟文件系统,以ASCII文本格式输出大量内核数据结构的内容,用户可以读取内容。</p>]]></content>
<summary type="html"><h1 id="第8章"><a href="#第8章" class="headerlink" title="第8章"></a>第8章</h1><h2 id="进程"><a href="#进程" class="headerlink" title="进程"></a>进程</h2><p</summary>
</entry>
<entry>
<title>angr-理解符号执行</title>
<link href="http://example.com/2022/02/16/angr-%E7%90%86%E8%A7%A3%E7%AC%A6%E5%8F%B7%E6%89%A7%E8%A1%8C/"/>
<id>http://example.com/2022/02/16/angr-%E7%90%86%E8%A7%A3%E7%AC%A6%E5%8F%B7%E6%89%A7%E8%A1%8C/</id>
<published>2022-02-16T04:10:22.000Z</published>
<updated>2022-02-16T04:48:50.124Z</updated>
<content type="html"><![CDATA[<h1 id="理解符号执行-angr"><a href="#理解符号执行-angr" class="headerlink" title="理解符号执行-angr"></a>理解符号执行-angr</h1><p>符号类似于我们在计算未知数x的值,我们可以通过路径来求解未知数。通过判断条件来选择路径,当符号满足设定条件时即走了正确的路径。</p><p>我们需要通过符号执行来达到一个目标,假设这个目标是走到success这一步。</p><p>那么我们符号执行的步骤就相当明了了。</p><p>第一步:找到符号。一般这里我们的未知数,即符号就是我们的input。</p><p>第二步:找到路径(分支)。</p><p>第三步:评估每条路径。</p><p>由于路径和二进制文件的复杂度提升,我们给出了更好的选择来通过电脑来评估路径,于是就有了angr</p><p>Angr是一个符号执行引擎。</p><p>它可以:</p><p>遍历二进制文件(并遵循任何分支)</p><p>搜索符合给定条件的程序状态</p><p>解给定路径(和其他)约束的符号变量</p><p>在这里分为<strong>符号</strong>和<strong>执行路径</strong>两个板块</p><p>首先讨论执行路径</p><h2 id="1-执行路径"><a href="#1-执行路径" class="headerlink" title="1.执行路径"></a>1.执行路径</h2><p>Angr在一个模拟管理器对象中存储和处理一组给定程序的可能路径。</p><p>模拟管理器提供了逐步执行程序以生成可能路径/状态的功能。</p><p><strong>构建一系列路径</strong></p><p>1.Angr在你指定的地方启动程序(这是第一个激活状态)</p><p>2.在每个活动(非终止)状态下执行指令,直到到达分支点或状态终止</p><p>3.在每个分支点上,将状态拆分为多个状态,并将它们添加到活动状态集</p><p>4.重复步骤2 . .4,直到我们找到我们想要的,否则所有的州都会被终止</p><p>我们可以对活动状态进行标记,以排除错误的路径。</p><p>1.加载二进制</p><p>2.指定起点并创建模拟管理器</p><p>3.当我们还没有找到我们想要的……</p><p>1)步进所有激活状态</p><p>2)在每个活动状态上运行’ should_accept_state ‘谓词</p><p>3)如果有人接受,我们就找到了我们想要的!退出循环</p><p>4)在每个活动状态上运行’ should_avoid_state ‘谓词</p><p>5)对于每个被接受的状态,将其标记为终止</p><p>6)从活动状态集中移除所有标记为终止的状态</p><p>这个算法angr写了一个单独的explore函数</p><p>simulation.explore(find=should_accept_path, avoid=should_avoid_path)</p><p>将添加任何被接受的路径到列表’ simulation.found ‘</p><p>simulation.explore(find= 0 x80430a,avoid= 0x9aa442)</p><p>将搜索地址0x80430a并终止任何到达0x9aa442的内容。</p><h2 id="2-符号和约束的引入"><a href="#2-符号和约束的引入" class="headerlink" title="2.符号和约束的引入"></a>2.符号和约束的引入</h2><p>在某些情况下,当从stdin文件中查询用户输入时,Angr会自动注入符号。*它使用的是SimProcedures,我们将在后面介绍。</p><p>当Angr没有自动注入我们想要的符号时,我们可以手动这样做。</p><p>Angr的符号是用位向量来表示的</p><p>位向量有一个大小,即它们所代表的位数。</p><p>与编程中的所有数据一样,位向量可以表示任何适合的类型。通常,它们表示n位整数或字符串。</p><p>位向量和典型变量之间的区别是,典型变量存储单个值,而位向量存储满足一定约束条件的所有值。</p><p>在简单的例子中,angr会自动将您的input作为符号注入,但在一些复杂的情况下需要手动输入</p><p>下面是一些例子:</p><p><strong>注入符号示例</strong></p><p>1.寄存器</p><p>对于简单的情况,Angr会代替它,这样用户输入函数就会将符号值注入寄存器。</p><p>对于更复杂的情况,我们需要自己注入符号。在用户输入后启动程序,用符号值初始化寄存器。</p><p>情形:get_user_input函数通过将值写入寄存器来返回值(把输入存在内存中,并把地址写到rax寄存器并返回)。(angr不支持写入多个参数于不同地址。)</p><p>解决方案:不调用get_user_input,而是将符号值写入寄存器。</p><p>在Angr中,你可以用一个具体的或符号的值写入寄存器:</p><p>state.regs.eax = my_bitvector</p><p>将my_bitvector的值写入eax。</p><p>2.全局内存</p><p>情形:get_user_input函数通过将值写入编译时确定的地址来返回值。</p><p>解决方案:不调用get_user_input,而是将符号值写入地址。</p><p>3.栈</p><p>在Angr中,你可以用一个具体的或符号的值来推入堆栈:</p><p>state.stack_push (my_bitvector)</p><p>将my_bitvector的值推到堆栈的顶部。</p><p>你可能需要考虑你不关心的任何东西在堆栈的开始通过添加填充:</p><p>state.regs.esp - = 4</p><p>增加4个字节的填充。</p><p>4.动态内存</p><p>分配在堆上的内存</p><p>可以直接写入到指针覆盖原有指针</p><p>如果你不能确定scanf写入的地址,因为它存储在一个指针中,你可以覆盖指针的值,指向你选择的一个未使用的位置(在这个例子中,0x4444444):</p><p>state.memory.store(0xaf84dd8, 0x4444444) state.memory.store(0x4444444, my_bitvector)</p><p>此时,0xaf84dd8的指针将指向0x4444444,它将存储您的位向量。</p><p>5.文件系统</p><p>可以当作内存处理,但地址和内存的地址不同,要注意</p><p><strong>特殊情况</strong></p><p>1.hooks</p><p>如果想要跳一些地址,可以使用hook</p><p>您可以使用hooks来完成此操作。你可以指定一个‘hook’的地址,你想要跳过的指令的字节数,以及一个将运行的Python函数来替换跳过的指令。</p><p>注意:跳过的指令数可以为零。</p><p>Call: binary.hook(0x8048776, length=16, replacement_check_all_Z)</p><p>第一个是我们想要hook的地址,第二个是代表这些指令在内存中用16个字节表示(跳过的),第三个是代替运行这些指令的函数。</p><p>Hook可以用于:</p><p>在执行过程中注入符号值。</p><p>取代复杂的功能。</p><p>替换不支持的指令(例如,大多数系统调用)。</p><p>函数回顾</p><ol><li>将参数推入堆栈</li><li>将返回地址推到堆栈</li><li>跳转到功能地址</li><li>处理参数*</li><li>执行函数</li><li>将返回值写入适当的位置</li><li>弹出返回地址并跳转到它</li><li>弹出参数</li></ol><p><strong>simprocedures</strong></p><p>SimProcedures被用来替换任何你完全理解并且不想测试bug的东西,或者Angr不支持的东西。</p><p>因为问题的复杂性随着程序的长度呈指数级增长,任何满足上述条件的函数都应该用SimProcedure代替,以节省时间。</p><p>目前,在Angr中包含了libc子集(快速扩展)的重新实现。</p>]]></content>
<summary type="html"><h1 id="理解符号执行-angr"><a href="#理解符号执行-angr" class="headerlink" title="理解符号执行-angr"></a>理解符号执行-angr</h1><p>符号类似于我们在计算未知数x的值,我们可以通过路径来求解未知数。通过</summary>
<category term="angr" scheme="http://example.com/tags/angr/"/>
</entry>
<entry>
<title>C++ Reserve 阅读</title>
<link href="http://example.com/2022/02/09/C-Reserve/"/>
<id>http://example.com/2022/02/09/C-Reserve/</id>
<published>2022-02-09T07:46:13.000Z</published>
<updated>2022-02-09T11:50:58.416Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>这是一个关于c++逆向的阅读材料,我大致做一些笔记,因为是全英文所以基本是翻译)</p><h2 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h2><p>c++中主要是类,在我们理解c++时,对于c++目标的主要部分(类)以及这些部分如何联系在一起(类关系)有一个宏观的概念。</p><p>为了实现这种理解,我们必须能够:</p><p>(1)识别类</p><p>(2)识别类之间的关系</p><p>(3)识别类成员。</p><p>而人工分析检索c++类信息方法和自动化是这篇文章要讨论的内容。</p><h2 id="手动分析c-二进制文件"><a href="#手动分析c-二进制文件" class="headerlink" title="手动分析c++二进制文件"></a>手动分析c++二进制文件</h2><p>本节介绍分析c++二进制文件的手动方法;它特别侧重于识别/提取c++类及其对应成员(变量、函数、构造函数/析构函数)和关系。请注意</p><p>首先,我们需要识别这是否是一个c++文件,或者运用了c++的类,下面几种可以判断:</p><p>1)大量使用ecx(这个ptr)。可能首先看到的事情之一是大量使用ecx(用作this指针)。可能看到的一个地方是,在函数即将被调用之前被赋值。另一种情况是,如果一个函数使用了ecx而没有首先初始化它,这意味着它可能是一个类成员函数。</p>.jpg).jpg)<p>2)调用约定。与(1)相关的是,类成员函数调用时使用堆栈中常用的函数参数,并指向类的对象(即thispointer.)。下面是一个类实例化的例子,在这个例子中,分配的类对象(eax)最终将被传递给ecx,然后调用构造函数</p>.jpg)<p>此外,我们将注意到更可能是虚函数的间接函数调用;当然,如果不首先知道实际的类或在调试器下运行代码,就很难跟踪这些调用的去向。在这种情况下,我们必须首先知道ClassA的虚函数表(vftable)的位置,然后根据虚函数表中列出的函数列表确定函数的实际地址。</p><img src="/2022/02/09/C-Reserve/4.jpg" class="" width="4"><p>3)STL代码和导入的dll。判断一个样本是否为c++二进制文件的另一种方法是,目标是否使用STL代码,这可以通过导入函数或库签名识别(如IDA的FLIRT)来判断.</p><img src="/2022/02/09/C-Reserve/5.jpg" class="" width="5"><h3 id="类布局"><a href="#类布局" class="headerlink" title="类布局"></a>类布局</h3><p>我们还应该熟悉类在内存中的布局方式。让我们从一个非常简单的类开始。</p><img src="/2022/02/09/C-Reserve/6.jpg" class="" width="6"><p>这个类的布局如图所示</p><img src="/2022/02/09/C-Reserve/7.jpg" class="" width="7"><p>为了保持4字节的边界上的对齐,填充被添加到最后一个成员变量。在Visual c++中,成员变量在内存中的位置与声明的顺序相同。</p><p>当类中包含虚函数:</p><img src="/2022/02/09/C-Reserve/8.jpg" class="" width="8"><p>内存布局将变成这样:</p><img src="/2022/02/09/C-Reserve/9.jpg" class="" width="9"><p>注意,在布局的开头添加了一个指向虚函数表的指针。该表按照虚函数声明的顺序包含虚函数的地址。类Ex2的虚函数表如下所示:</p><img src="/2022/02/09/C-Reserve/10.jpg" class="" width="10"><p>如果一个类继承另一个类呢?以下是一个类从单个类继承时的情况,即单个继承:</p><img src="/2022/02/09/C-Reserve/11-16444044998161.jpg" class="" width="11"><p>布局是这样的</p><img src="/2022/02/09/C-Reserve/12.jpg" class="" width="12"><p>派生类的布局被简单地附加到基类的布局中。在多重继承的情况下,会发生以下情况:</p><img src="/2022/02/09/C-Reserve/13.jpg" class="" width="13"><img src="/2022/02/09/C-Reserve/14.jpg" class="" width="14"><p>正如所看到的,每个基类的实例数据的副本将被嵌入到派生类的实例中,每个包含虚函数的基类将有自己的vftable。注意,第一个基类与当前对象共享一个vftable。当前对象的虚函数将被追加到第一个基类的虚函数列表的末尾。</p>]]></content>
<summary type="html"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>这是一个关于c++逆向的阅读材料,我大致做一些笔记,因为是全英文所以基本是翻译)</p>
<h2 id="介绍"><a href="#介绍"</summary>
<category term="-----" scheme="http://example.com/tags/"/>
</entry>
<entry>
<title>pwn入门体验</title>
<link href="http://example.com/2022/01/19/pwnstart/"/>
<id>http://example.com/2022/01/19/pwnstart/</id>
<published>2022-01-18T17:19:57.000Z</published>
<updated>2022-01-18T17:26:01.384Z</updated>
<content type="html"><![CDATA[<h2 id="Water"><a href="#Water" class="headerlink" title="Water"></a>Water</h2><p>today i do nothing but i open the test of pwn, so……,my first blog in 2022</p><h2 id="Start"><a href="#Start" class="headerlink" title="Start"></a>Start</h2><p>2022的第一篇博客,因为没接触过pwn就从攻防世界的新手题跟着做开始,找了一个视频跟着学和写,刚接触下来还是觉得比较有意思,但是听说看东西很折磨人)</p><h2 id="Point"><a href="#Point" class="headerlink" title="Point"></a>Point</h2><p>最开始的做题步骤首先是查位数,逆向中一般直接使用DIE就可以,在pwn里面可以直接file来查看文件的位数,这在编写exp文件的时候需要。然后是checksec命令,帮助我们看开了甚么保护。但打保护这方面我还没有学到,记得查就对了,养成好习惯。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">1 -- file 文件名</span><br><span class="line">2 -- checksec --file=文件名</span><br></pre></td></tr></table></figure><img src="/2022/01/19/pwnstart/1.png" class="" width="1">这里可以看到是一个32位的文件了,下一步是在ida里进行静态分析,然后确定漏洞类型,整理逻辑。<h3 id="栈溢出"><a href="#栈溢出" class="headerlink" title="栈溢出"></a>栈溢出</h3><p>一开始的题就是栈溢出,比较好理解。通过溢出覆盖字节为你想要的内容来得到flag。一般都会有if语句判断数据是否等于一个规定的数据,通过溢出写入数据就可以达成目的。</p><h3 id="溢出点"><a href="#溢出点" class="headerlink" title="溢出点"></a>溢出点</h3><p>关于我做了一丢丢题,一般溢出点都会是buf等等,通过write,read,get等函数来溢出。要注意有漏洞的函数然后观察是否有溢出的可能性。</p><h3 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h3><p>有一道题他需要溢出14+4个字节,但检验了填入数据的长度3-8,也就是说没办法填入那么多垃圾数据来溢出,这里解决的方法是转眼到了数据类型,因为是unsigned short int,所以用8bit位来算0x101就变成了0x1,即可以257 + 2 ~ 257 + 7都可以通过检测。</p><h3 id="system"><a href="#system" class="headerlink" title="system"></a>system</h3><p>system函数与plt表和got表有关,在用于构造跳转时经常会用到两个表,有system函数说明在plt表中有该函数的地址,溢出返回地址需要为它的地址。跳转到返回地址后填入数据再写入想要的数据。在pwn题里经常需要构造结构来写payload去写入数据,要搞清楚思路和栈里的结构就会很好写脚本。</p><h3 id="libc泄露"><a href="#libc泄露" class="headerlink" title="libc泄露"></a>libc泄露</h3><p>libc文件和文件中的地址是不同的,不能直接用文件中的地址去打,会找到错误的地方,但地址之间的偏移量是固定的,所以可以计算文件和libc文件中的相应函数之间的固定偏移量,运用偏移量来寻址。从而继续构造结构来写脚本的payload。</p><h3 id="格式化字符串漏洞"><a href="#格式化字符串漏洞" class="headerlink" title="格式化字符串漏洞"></a>格式化字符串漏洞</h3><p>还没仔细看资料,只是知道有这个东西,可以配合%n来写入数据,格式化字符串漏洞一般都需要调试文件,写入测试数据和一堆%p(地址)来找到漏洞的位置以便写入文件需要的数据。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">%c:输出字符,配上%n可用于向指定地址写数据。</span><br><span class="line"></span><br><span class="line">%d:输出十进制整数,配上%n可用于向指定地址写数据。</span><br><span class="line"></span><br><span class="line">%x:输出16进制数据,如%i$x表示要泄漏偏移i处4字节长的16进制数据,%i$lx表示要泄漏偏移i处8字节长的16进制数据,32bit和64bit环境下一样。</span><br><span class="line"></span><br><span class="line">%p:输出16进制数据,与%x基本一样,只是附加了前缀0x,在32bit下输出4字节,在64bit下输出8字节,可通过输出字节的长度来判断目标环境是32bit还是64bit。</span><br><span class="line"></span><br><span class="line">%s:输出的内容是字符串,即将偏移处指针指向的字符串输出,如%i$s表示输出偏移i处地址所指向的字符串,在32bit和64bit环境下一样,可用于读取GOT表等信息。</span><br><span class="line"></span><br><span class="line">%n:将%n之前printf已经打印的字符个数赋值给偏移处指针所指向的地址位置,如%100×10$n表示将0x64写入偏移10处保存的指针所指向的地址(4字节),而%$hn表示写入的地址空间为2字节,%$hhn表示写入的地址空间为1字节,%$lln表示写入的地址空间为8字节,在32bit和64bit环境下一样。有时,直接写4字节会导致程序崩溃或等候时间过长,可以通过%$hn或%$hhn来适时调整。</span><br><span class="line"></span><br><span class="line">%n是通过格式化字符串漏洞改变程序流程的关键方式,而其他格式化字符串参数可用于读取信息或配合%n写数据。</span><br></pre></td></tr></table></figure><h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><p>攻防世界新手区详细的每道题解在这里<a href="http://www.peiqi.tech/posts/7499/#when-did-you-born">http://www.peiqi.tech/posts/7499/#when-did-you-born</a></p><h2 id="exp-py"><a href="#exp-py" class="headerlink" title="exp.py"></a>exp.py</h2><p>通过写exp.py文件来打,模板和注意就放在这里。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line"></span><br><span class="line">context(os = <span class="string">'linux'</span>, arch = <span class="string">'x86'</span>, log_level = <span class="string">'debug'</span>) <span class="comment">#x86是32位文件,amd64就是64位文件</span></span><br><span class="line">content = <span class="number">0</span> <span class="comment">#攻击远程,打本地是1</span></span><br><span class="line">pwn_addr = <span class="number">0x0804A068</span> <span class="comment">#一般将地址写在这里</span></span><br><span class="line"><span class="comment">#如果是elf文件中可以寻址</span></span><br><span class="line"><span class="comment">#elf = ELF("level3") elf文件寻址需要写这个</span></span><br><span class="line"><span class="comment">#lib = ELF("libc_32.so.6") libc文件寻址需要写这个</span></span><br><span class="line"><span class="comment">#write_plt_addr = elf.plt["write"]</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span>():</span> <span class="comment">#main函数</span></span><br><span class="line"> <span class="keyword">global</span> sh</span><br><span class="line"> <span class="keyword">if</span> content == <span class="number">1</span>: <span class="comment">#打本地</span></span><br><span class="line"> sh = process(<span class="string">'CGfsb'</span>) <span class="comment">#文件名</span></span><br><span class="line"> <span class="keyword">else</span>: <span class="comment">#打远程</span></span><br><span class="line"> sh = remote(<span class="string">"111.200.241.244"</span>,<span class="number">63601</span>) <span class="comment">#端口和ip</span></span><br><span class="line"></span><br><span class="line"> payload = p32(pwn_addr) + <span class="string">b'aaaa'</span> + <span class="string">b'%10$n'</span> <span class="comment">#payload一般就是写入,填入数据的话需要以byte(字节流)的形式填入,不然会出错,这里的写入的地址等都要以p32或者p64来打包</span></span><br><span class="line"> sh.sendlineafter(<span class="string">"please tell me your name:\n"</span>,<span class="string">"1"</span>) <span class="comment">#sendlineafter,前面是程序中的语句,后面是你需要输入的东西</span></span><br><span class="line"> sh.sendlineafter(<span class="string">"leave your message please:\n"</span>,payload)</span><br><span class="line"></span><br><span class="line"> sh.interactive()<span class="comment">#接收信息</span></span><br><span class="line"> </span><br><span class="line">main()</span><br></pre></td></tr></table></figure><h2 id="END"><a href="#END" class="headerlink" title="END"></a>END</h2><p>少打音游多读书</p>]]></content>
<summary type="html"><h2 id="Water"><a href="#Water" class="headerlink" title="Water"></a>Water</h2><p>today i do nothing but i open the test of pwn, so……,my fir</summary>
<category term="0-1--pwn" scheme="http://example.com/tags/0-1-pwn/"/>
</entry>
<entry>
<title>XXTEA python</title>
<link href="http://example.com/2021/12/30/XXTEA-python/"/>
<id>http://example.com/2021/12/30/XXTEA-python/</id>
<published>2021-12-30T07:57:58.000Z</published>
<updated>2021-12-30T13:54:30.499Z</updated>
<content type="html"><![CDATA[<h2 id="XXTEA-python-加密-解密脚本"><a href="#XXTEA-python-加密-解密脚本" class="headerlink" title="XXTEA python 加密/解密脚本"></a>XXTEA python 加密/解密脚本</h2><h2 id="Start"><a href="#Start" class="headerlink" title="Start"></a>Start</h2><p>normal24里面终于遇到了xxtea了,新加密get,找比较好的解密脚本也花了不少时间。另外还有tea和xtea的,这个写的头疼等摆一会有空补上。</p><p>参考<a href="http://www.yaowenming.com/A/8Bz8qZ6XJx/">http://www.yaowenming.com/A/8Bz8qZ6XJx/</a></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> struct</span><br><span class="line"></span><br><span class="line">_DELTA = <span class="number">0x9E3779B9</span> <span class="comment">#固定常量</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_long2str</span>(<span class="params">v, w</span>):</span></span><br><span class="line"> n = (<span class="built_in">len</span>(v) - <span class="number">1</span>) << <span class="number">2</span></span><br><span class="line"> <span class="keyword">if</span> w:</span><br><span class="line"> m = v[-<span class="number">1</span>]</span><br><span class="line"> <span class="keyword">if</span> (m < n - <span class="number">3</span>) <span class="keyword">or</span> (m > n): <span class="keyword">return</span> <span class="string">''</span></span><br><span class="line"> n = m</span><br><span class="line"> s = struct.pack(<span class="string">'<%iL'</span> % <span class="built_in">len</span>(v), *v)</span><br><span class="line"> <span class="keyword">return</span> s[<span class="number">0</span>:n] <span class="keyword">if</span> w <span class="keyword">else</span> s</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_str2long</span>(<span class="params">s, w</span>):</span></span><br><span class="line"> n = <span class="built_in">len</span>(s)</span><br><span class="line"> m = (<span class="number">4</span> - (n & <span class="number">3</span>) & <span class="number">3</span>) + n</span><br><span class="line"> s = s.ljust(m, <span class="string">b"\0"</span>)</span><br><span class="line"> v = <span class="built_in">list</span>(struct.unpack(<span class="string">'<%iL'</span> % (m >> <span class="number">2</span>), s))</span><br><span class="line"> <span class="keyword">if</span> w: v.append(n)</span><br><span class="line"> <span class="keyword">return</span> v</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">encrypt</span>(<span class="params"><span class="built_in">str</span>, key</span>):</span> <span class="comment">#加密部分</span></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">str</span> == <span class="string">''</span>: <span class="keyword">return</span> <span class="built_in">str</span></span><br><span class="line"> v = _str2long(<span class="built_in">str</span>, <span class="literal">True</span>)</span><br><span class="line"> k = _str2long(key.ljust(<span class="number">16</span>, <span class="string">b"\0"</span>), <span class="literal">False</span>)</span><br><span class="line"> n = <span class="built_in">len</span>(v) - <span class="number">1</span></span><br><span class="line"> z = v[n]</span><br><span class="line"> y = v[<span class="number">0</span>]</span><br><span class="line"> <span class="built_in">sum</span> = <span class="number">0</span></span><br><span class="line"> q = <span class="number">6</span> + <span class="number">52</span> // (n + <span class="number">1</span>) <span class="comment">#得出轮数</span></span><br><span class="line"> <span class="keyword">while</span> q > <span class="number">0</span>:</span><br><span class="line"> <span class="built_in">sum</span> = (<span class="built_in">sum</span> + _DELTA) & <span class="number">0xffffffff</span> <span class="comment">#进行叠加</span></span><br><span class="line"> e = <span class="built_in">sum</span> >> <span class="number">2</span> & <span class="number">3</span> <span class="comment">#固定运算</span></span><br><span class="line"> <span class="keyword">for</span> p <span class="keyword">in</span> <span class="built_in">range</span>(n):</span><br><span class="line"> y = v[p + <span class="number">1</span>]</span><br><span class="line"> v[p] = (v[p] + ((z >> <span class="number">5</span> ^ y << <span class="number">2</span>) + (y >> <span class="number">3</span> ^ z << <span class="number">4</span>) ^ (<span class="built_in">sum</span> ^ y) + (k[p & <span class="number">3</span> ^ e] ^ z))) & <span class="number">0xffffffff</span></span><br><span class="line"> z = v[p]</span><br><span class="line"> y = v[<span class="number">0</span>]</span><br><span class="line"> v[n] = (v[n] + ((z >> <span class="number">5</span> ^ y << <span class="number">2</span>) + (y >> <span class="number">3</span> ^ z << <span class="number">4</span>) ^ (<span class="built_in">sum</span> ^ y) + (k[n & <span class="number">3</span> ^ e] ^ z))) & <span class="number">0xffffffff</span> <span class="comment">#xxtea加密的标识性加密步骤</span></span><br><span class="line"> z = v[n]</span><br><span class="line"> q -= <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> _long2str(v, <span class="literal">False</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">decrypt</span>(<span class="params"><span class="built_in">str</span>, key</span>):</span> <span class="comment">#解密部分</span></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">str</span> == <span class="string">''</span>: <span class="keyword">return</span> <span class="built_in">str</span></span><br><span class="line"> v = _str2long(<span class="built_in">str</span>, <span class="literal">False</span>)</span><br><span class="line"> k = _str2long(key.ljust(<span class="number">16</span>, <span class="string">b"\0"</span>), <span class="literal">False</span>)</span><br><span class="line"> n = <span class="built_in">len</span>(v) - <span class="number">1</span></span><br><span class="line"> z = v[n]</span><br><span class="line"> y = v[<span class="number">0</span>]</span><br><span class="line"> q = <span class="number">6</span> + <span class="number">52</span> // (n + <span class="number">1</span>)</span><br><span class="line"> <span class="built_in">sum</span> = (q * _DELTA) & <span class="number">0xffffffff</span></span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">sum</span> != <span class="number">0</span>):</span><br><span class="line"> e = <span class="built_in">sum</span> >> <span class="number">2</span> & <span class="number">3</span></span><br><span class="line"> <span class="keyword">for</span> p <span class="keyword">in</span> <span class="built_in">range</span>(n, <span class="number">0</span>, -<span class="number">1</span>):</span><br><span class="line"> z = v[p - <span class="number">1</span>]</span><br><span class="line"> v[p] = (v[p] - ((z >> <span class="number">5</span> ^ y << <span class="number">2</span>) + (y >> <span class="number">3</span> ^ z << <span class="number">4</span>) ^ (<span class="built_in">sum</span> ^ y) + (k[p & <span class="number">3</span> ^ e] ^ z))) & <span class="number">0xffffffff</span></span><br><span class="line"> y = v[p]</span><br><span class="line"> z = v[n]</span><br><span class="line"> v[<span class="number">0</span>] = (v[<span class="number">0</span>] - ((z >> <span class="number">5</span> ^ y << <span class="number">2</span>) + (y >> <span class="number">3</span> ^ z << <span class="number">4</span>) ^ (<span class="built_in">sum</span> ^ y) + (k[<span class="number">0</span> & <span class="number">3</span> ^ e] ^ z))) & <span class="number">0xffffffff</span></span><br><span class="line"> y = v[<span class="number">0</span>]</span><br><span class="line"></span><br><span class="line"> <span class="built_in">sum</span> = (<span class="built_in">sum</span> - _DELTA) & <span class="number">0xffffffff</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> _long2str(v, <span class="literal">True</span>)</span><br></pre></td></tr></table></figure><p>解密使用示例</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">flag = [<span class="number">188</span>, <span class="number">165</span>, <span class="number">206</span>, <span class="number">64</span>, <span class="number">244</span>, <span class="number">178</span>, <span class="number">178</span>, <span class="number">231</span>, <span class="number">169</span>, <span class="number">18</span>, <span class="number">157</span>, <span class="number">18</span>, <span class="number">174</span>, <span class="number">16</span>, <span class="number">200</span>, <span class="number">91</span>, <span class="number">61</span>, <span class="number">215</span>, <span class="number">6</span>, <span class="number">29</span>, <span class="number">220</span>, <span class="number">112</span>, <span class="number">248</span>, <span class="number">220</span>]</span><br><span class="line"></span><br><span class="line">x = decrypt(<span class="built_in">bytes</span>(flag),<span class="string">'flag'</span>.encode()) flag就是四位数的key</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(x)</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h2 id="XXTEA-python-加密-解密脚本"><a href="#XXTEA-python-加密-解密脚本" class="headerlink" title="XXTEA python 加密/解密脚本"></a>XXTEA python 加密/解密脚本</h2><</summary>
</entry>
<entry>
<title>csapp-pra1</title>
<link href="http://example.com/2021/12/18/postcsapp-pra1/"/>
<id>http://example.com/2021/12/18/postcsapp-pra1/</id>
<published>2021-12-18T07:50:46.000Z</published>
<updated>2021-12-18T08:51:40.736Z</updated>
<content type="html"><![CDATA[<h2 id="Starts"><a href="#Starts" class="headerlink" title="Starts"></a>Starts</h2><p>断断续续总算把csapp的第一章看完了,算是非常基础的介绍部分,介绍了很多计算机硬件的知识和常识,以及后面章节会涉及到的一些学习的内容。</p><h3 id="编译系统"><a href="#编译系统" class="headerlink" title="编译系统"></a>编译系统</h3><p>说实话,了解原理还算比较有趣的,从helloworld程序讲起。从源文件到编译成可执行目标文件需要经过四个阶段,分别由预处理器,编译器,汇编器,链接器,他们构成了编译系统。而我们需要去了解编译系统是如何工作的,这样才能够实现优化程序性能,理解链接时出现的错误,避免安全漏洞。里面会用到汇编,链接和算法的知识,在我们写程序时常常会有运行复杂和安全性的区别,了解编译系统是至关重要的。</p><h3 id="处理器读取解释指令"><a href="#处理器读取解释指令" class="headerlink" title="处理器读取解释指令"></a>处理器读取解释指令</h3><p>当编译结束后系统硬件需要工作来执行可执行文件。硬件组成由总线,I/O设备,主存,处理器。而执行在硬件里数据需要加载到主存,处理器执行机器语言指令,通过总线达到寄存器再存放到内存中。而运行中需要速度,所以引入了高速缓存的概念,采用高速缓存存储器L1L2L3多级访问可以实现程序性能的显著提高,存储器层次结构呈金字塔型,高速缓存和寄存器大大提高了存储的效率。</p><h3 id="操作系统(抽象)"><a href="#操作系统(抽象)" class="headerlink" title="操作系统(抽象)"></a>操作系统(抽象)</h3><p>操作系统管理硬件,防止硬件被失控的程序滥用,向应用程序提供简单已知的机制来控制复杂而又通常大不相同的低级硬件设备。</p><p>其中抽象概念十分重要,通过抽象概念来实现操作系统的功能,也是我们经常会听到的进程,虚拟内存和文件,实际上,文件是对I/O设备的抽象表示,虚拟内存是对主存和I/O设备的抽象表示,进程则是对处理器、主存和I/O设备的抽象表示。</p><p>在单处理器中实际上是在不断切换执行的进程。操作系统跟踪程序运行信息,而进程转换是由操作系统内核管理,例如读写程序需要执行sys call系统调用,给予内核控制权,结束后返回控制权,而实现进程需要硬件和软件的共同合作。</p><p>实际上进程中有并发和并行的概念,而线程级并发和指令级并行,超线程和多核处理器的出现也是提高系统性能的一大部分。线程即为控制流,多线程是现代提高程序运行程序的方式之一。虚拟内存是一种每个进程都在独占使用主存,被称为虚拟地址空间,其中有只读的代码和数据,堆,栈,共享库,内核虚拟内存等等,地址从低到高增大。文件即为字节序列,作为读写的源。</p><h3 id="other"><a href="#other" class="headerlink" title="other"></a>other</h3><p>后面还多花了一些篇幅谈了并发和并行,以及抽象的重要性,和Amdahl定律(即加速比,想要提高整个系统的速度,需要提高全系统中相当大的部分的速度)。</p><h2 id="END"><a href="#END" class="headerlink" title="END"></a>END</h2><p>系统漫游简略带我领略了一下计算机世界和我们可以在哪里来实现对程序等等计算机中的部件的运行的优化,更好的实现一个程序以及很多的更好的实现。或许不断完善和探究原理不仅是对一个系统,一个程序,一个计算机的要求,也应该是对自己的要求吧。</p><p>Waste It On Me.</p>]]></content>
<summary type="html"><h2 id="Starts"><a href="#Starts" class="headerlink" title="Starts"></a>Starts</h2><p>断断续续总算把csapp的第一章看完了,算是非常基础的介绍部分,介绍了很多计算机硬件的知识和常识,以及后面章</summary>
<category term="csapp" scheme="http://example.com/tags/csapp/"/>
</entry>
<entry>
<title>多个ELF文件分析处理与自解密IDApython使用</title>
<link href="http://example.com/2021/12/15/%E5%A4%9A%E4%B8%AAELF%E6%96%87%E4%BB%B6%E5%88%86%E6%9E%90%E5%A4%84%E7%90%86%E4%B8%8E%E8%87%AA%E8%A7%A3%E5%AF%86IDApython%E4%BD%BF%E7%94%A8/"/>
<id>http://example.com/2021/12/15/%E5%A4%9A%E4%B8%AAELF%E6%96%87%E4%BB%B6%E5%88%86%E6%9E%90%E5%A4%84%E7%90%86%E4%B8%8E%E8%87%AA%E8%A7%A3%E5%AF%86IDApython%E4%BD%BF%E7%94%A8/</id>
<published>2021-12-15T06:33:18.000Z</published>
<updated>2021-12-19T08:19:08.084Z</updated>
<content type="html"><![CDATA[<h2 id="starts"><a href="#starts" class="headerlink" title="starts"></a>starts</h2><p>这篇其实是对normal11的wp的一个复现,因为学习到了很多没接触过的东西所以想做一个归纳,以后查看的时候也比较方便。wp写的比较简略,只是给了一个大致的思路,需要搞懂还是要手操一遍才会发现自己哪里不会。</p><h2 id="多可执行文件的分析处理"><a href="#多可执行文件的分析处理" class="headerlink" title="多可执行文件的分析处理"></a>多可执行文件的分析处理</h2><p>首先是关键代码不在main里面,main函数里有很复杂的代码,看起来并不像关键代码。这里可以在start开始下断点然后跟进看会先走哪里。跟着wp查看init(main)函数前调用的函数,点进去看调用了一个可疑函数sub_400976,然后通过问和查资料了解了一下这段代码的意思。</p><img src="/2021/12/15/%E5%A4%9A%E4%B8%AAELF%E6%96%87%E4%BB%B6%E5%88%86%E6%9E%90%E5%A4%84%E7%90%86%E4%B8%8E%E8%87%AA%E8%A7%A3%E5%AF%86IDApython%E4%BD%BF%E7%94%A8/2.png" class="" width="2"><p>就是从结尾开始读取12936个字节,当作文件运行。也就是这个文件里有两个可执行文件(ELF).可以使用winhex来把第二个ELF文件抠出来,单独分析。把文件拖进winhex里,从ELF头选中整个文件,右击编辑另存为到新的文件里。</p><h2 id="SMC自解密与IDApython的使用"><a href="#SMC自解密与IDApython的使用" class="headerlink" title="SMC自解密与IDApython的使用"></a>SMC自解密与IDApython的使用</h2><p>重新使用ida查看新生成的文件的关键代码这时候就能看到一个SMC自解密,即为这个encrypt。</p><img src="/2021/12/15/%E5%A4%9A%E4%B8%AAELF%E6%96%87%E4%BB%B6%E5%88%86%E6%9E%90%E5%A4%84%E7%90%86%E4%B8%8E%E8%87%AA%E8%A7%A3%E5%AF%86IDApython%E4%BD%BF%E7%94%A8/1.png" class="" width="1"><p>上网查了一下什么是SMC自解密。即<strong>自修改代码</strong>,简而言之就是程序中的部分代码在运行前是被加密成一段数据,不可反编译,通过程序运行后执行相关解码代功能,对加密的代码数据进行解密,让其恢复正常功能。这里使用idapython来进行解密。wp里的idapython指令是ida7.5以前的指令版本,我这里使用的是ida7.6,所以不能使用旧版的指令,顺带学习了一下idapython的使用。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">addr = <span class="number">0xAF0</span> <span class="comment">#encrypt的地址</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">310</span>):</span><br><span class="line"> ida_bytes.patch_byte(addr+i+<span class="number">20</span>,idc.get_wide_byte(addr+i+<span class="number">20</span>)^i)</span><br><span class="line"><span class="comment">#idc.get_wide_byte(addr):以字节为单位获取地址处的值,旧版中为Byte(addr)</span></span><br><span class="line"><span class="comment">#修改指令的值:ida_bytes.patch_byte(addr,value)(addr,value):修改addr地址的值为value.每次修改一个字节</span></span><br></pre></td></tr></table></figure><p>详细了解idapython这些的用法可以看看这一篇</p><p><a href="https://www.cnblogs.com/iBinary/p/14642662.html">https://www.cnblogs.com/iBinary/p/14642662.html</a></p><p>IDApython run后查看汇编,这里还有一个字节(地址:B14)影响了反编译,把这个字节nop掉。</p><p>对encrypt函数按P从当前地址处解析成函数,再按U解析成未定义的内容。就可以成功反编译代码了,就是一个rc4加密,密文和密钥都给清楚了,还是比较容易分析的。但离谱的是wp的脚本竟然是用c写的,这时候一定要用py整个脚本自己写出来。</p><h2 id="RC4解密"><a href="#RC4解密" class="headerlink" title="RC4解密"></a>RC4解密</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">key = <span class="string">'hgame!@#'</span></span><br><span class="line">T = [key[i%<span class="built_in">len</span>(key)] <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">256</span>)]</span><br><span class="line">S = [i <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">256</span>)]</span><br><span class="line">text_lenth = <span class="number">27</span></span><br><span class="line">key_list = []</span><br><span class="line">text = [<span class="number">67</span>,<span class="number">36</span>,-<span class="number">27</span>,-<span class="number">95</span>,-<span class="number">59</span>,<span class="number">29</span>,<span class="number">114</span>,-<span class="number">46</span>,<span class="number">40</span>,-<span class="number">17</span>,-<span class="number">66</span>,-<span class="number">22</span>,-<span class="number">91</span>,-<span class="number">105</span>,<span class="number">68</span>,<span class="number">96</span>,-<span class="number">39</span>,<span class="number">15</span>,<span class="number">44</span>,<span class="number">111</span>,<span class="number">94</span>,<span class="number">38</span>,-<span class="number">77</span>,<span class="number">10</span>,-<span class="number">4</span>,-<span class="number">44</span>,-<span class="number">77</span>]</span><br><span class="line"></span><br><span class="line">j = <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">256</span>):</span><br><span class="line"> j = (j + S[i] + <span class="built_in">ord</span>(T[i])) % <span class="number">256</span></span><br><span class="line"> temp = S[j]</span><br><span class="line"> S[j] = S[i]</span><br><span class="line"> S[i] = temp</span><br><span class="line"></span><br><span class="line">i=<span class="number">0</span></span><br><span class="line">j=<span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> k <span class="keyword">in</span> <span class="built_in">range</span>(text_lenth):</span><br><span class="line"> i = (i+<span class="number">1</span>) % <span class="number">256</span></span><br><span class="line"> j = (j+S[i]) % <span class="number">256</span></span><br><span class="line"> temp = S[j]</span><br><span class="line"> S[j] = S[i]</span><br><span class="line"> S[i] = temp</span><br><span class="line"> t = (S[i]+S[j]) % <span class="number">256</span></span><br><span class="line"> key_list.append(S[t])</span><br><span class="line"></span><br><span class="line">ciphertext = [text[i]^key_list[i] <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">27</span>)]</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">27</span>):</span><br><span class="line"> ciphertext[i] &= <span class="number">0xff</span> <span class="comment">#因为这里计算出的ciphertext明文是负数,想要转化成chr必须进行高位清零,不然会报错</span></span><br><span class="line">ciphertext = [<span class="built_in">chr</span>(i) <span class="keyword">for</span> i <span class="keyword">in</span> ciphertext]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">''</span>.join(ciphertext))</span><br></pre></td></tr></table></figure><p>flag:hgame{th1s_f4ke_re4l_w0rld}</p><h2 id="END"><a href="#END" class="headerlink" title="END"></a>END</h2><p>知识在题目里会越来越综合着去使用,每次都要把东西搞清楚记下来捏。</p>]]></content>
<summary type="html"><h2 id="starts"><a href="#starts" class="headerlink" title="starts"></a>starts</h2><p>这篇其实是对normal11的wp的一个复现,因为学习到了很多没接触过的东西所以想做一个归纳,以后查看的时候</summary>
<category term="归纳" scheme="http://example.com/tags/%E5%BD%92%E7%BA%B3/"/>
</entry>
<entry>
<title>Z3约束求解器</title>
<link href="http://example.com/2021/12/13/Z3%E7%BA%A6%E6%9D%9F%E6%B1%82%E8%A7%A3%E5%99%A8/"/>
<id>http://example.com/2021/12/13/Z3%E7%BA%A6%E6%9D%9F%E6%B1%82%E8%A7%A3%E5%99%A8/</id>
<published>2021-12-13T13:48:07.000Z</published>
<updated>2021-12-14T12:24:55.504Z</updated>
<content type="html"><![CDATA[<h2 id="starts"><a href="#starts" class="headerlink" title="starts"></a>starts</h2><p>一直不会用z3,但是爆破里面经常会需要z3来一把梭,主要是在类型转换时里面经常有个a开头的类型搞我,给我整寄了。直到现在从normal题再一次做起又碰到z3的时候想起来还是需要学习一下,这次找到了一篇比较详细的讲解。</p><h2 id="Z3约束求解器"><a href="#Z3约束求解器" class="headerlink" title="Z3约束求解器"></a>Z3约束求解器</h2><p>安装z3模块</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install z3-solver</span><br></pre></td></tr></table></figure><p>在使用z3时,开头需要这样一行</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> z3 <span class="keyword">import</span> *</span><br></pre></td></tr></table></figure><h2 id="设置变量"><a href="#设置变量" class="headerlink" title="设置变量"></a>设置变量</h2><p>一般来使用z3大多数都会有位运算,所以一般就不用管Real(实数)和Int(整数),直接把变量设置成向量型就可以。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 声明单个 16 位的变量</span></span><br><span class="line">x = BitVec(<span class="string">'x'</span>,<span class="number">16</span>)</span><br><span class="line"><span class="comment"># 声明多个 16 位的变量</span></span><br><span class="line">y,z = BitVecs(<span class="string">'y z'</span>,<span class="number">16</span>)</span><br></pre></td></tr></table></figure><p>然后我们在z3里一般都会使用很多变量,需要快速添加变量。</p><p>添加 50 个 16 位 BitVec 变量 s :</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">s=[BitVec (<span class="string">'s%d'</span> % i,<span class="number">16</span>) <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">50</span>)] <span class="comment">#声明一个列表,数据类型是向量,向量的大小是16位</span></span><br><span class="line">flag = [BitVec(<span class="string">'%d'</span> % i, <span class="number">8</span>) <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">36</span>)] <span class="comment">#声名一个列表,数据类型是向量,大小是8位</span></span><br></pre></td></tr></table></figure><h2 id="创建约束求解器"><a href="#创建约束求解器" class="headerlink" title="创建约束求解器"></a>创建约束求解器</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">s = Solver()</span><br></pre></td></tr></table></figure><h2 id="添加约束条件"><a href="#添加约束条件" class="headerlink" title="添加约束条件"></a>添加约束条件</h2><p>以行为单位添加方程等式样子的约束条件:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">s.add(x**<span class="number">2</span>+y**<span class="number">2</span>==<span class="number">74</span>)</span><br><span class="line">s.add(x**<span class="number">5</span>-y==z)</span><br><span class="line"><span class="comment"># [y = -7, x = 5, z = 3132]</span></span><br></pre></td></tr></table></figure><p>这里注意,z3不允许列表与列表之间添加==约束条件,会报错。</p><h2 id="判断是否有解"><a href="#判断是否有解" class="headerlink" title="判断是否有解"></a>判断是否有解</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> s.check() == sat: <span class="comment">#检查是否有解</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"solver"</span>)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"no solver"</span>)</span><br></pre></td></tr></table></figure><h2 id="求解并输出"><a href="#求解并输出" class="headerlink" title="求解并输出"></a>求解并输出</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ans = s.model() <span class="comment">#求解</span></span><br><span class="line"><span class="built_in">print</span>(ans)</span><br></pre></td></tr></table></figure><h2 id="TIP"><a href="#TIP" class="headerlink" title="TIP"></a>TIP</h2><p>一般来说经常会使用z3来爆破,求解flag时需要将变量约束在可见字符的ascii码之内</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">s.add(x < <span class="number">127</span>)</span><br><span class="line">s.add(x >= <span class="number">32</span>)</span><br></pre></td></tr></table></figure><p>在约束条件时最好使用下标索引,用列表来管理(可以使输出是有序的)</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">s.add(s[<span class="number">18</span>] * s[<span class="number">8</span>] == <span class="number">5</span>)</span><br><span class="line">s.add(s[<span class="number">4</span>] * s[<span class="number">11</span>] == <span class="number">0</span>)</span><br></pre></td></tr></table></figure><p>求解打印结果</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">answer=s.model() <span class="comment">#求解</span></span><br><span class="line"><span class="comment">#print(answer)</span></span><br><span class="line">result=<span class="string">""</span>.join([<span class="built_in">str</span>(answer[i]) <span class="keyword">for</span> i <span class="keyword">in</span> s]) <span class="comment">#连接</span></span><br><span class="line"><span class="built_in">print</span>(result)</span><br></pre></td></tr></table></figure><h2 id="z3-ArithRef"><a href="#z3-ArithRef" class="headerlink" title="z3.ArithRef"></a>z3.ArithRef</h2><p>这个arithref,应该一开始使用z3的都会收到一个类型转换的报错。这是一个z3的特有变量类型,即使求解成功,也不能直接将这个类型的变量输出,在这里我们需要将变量进行类型转换才能成功的输出我们想要的数据。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">m = s.model()</span><br><span class="line"><span class="comment"># 输出为int类型</span></span><br><span class="line">a_int = m[a].as_long()</span><br><span class="line"><span class="comment"># 输出为fraction类型</span></span><br><span class="line">d_float = m[d].as_fraction()</span><br></pre></td></tr></table></figure><p>fraction类型的数据可以直接转换成float类型:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">float</span>(d_float)</span><br><span class="line">Out[<span class="number">31</span>]: <span class="number">3.0</span></span><br></pre></td></tr></table></figure><p>一般来说不会整那些精度活,如果输出无理数那也没法转化成chr类型了,如果有那种报错在题里一般都是自己写错了,检查一下思路和数据。</p><h2 id="例题"><a href="#例题" class="headerlink" title="例题"></a>例题</h2><p>贴个normal8上去捏</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> z3 <span class="keyword">import</span>*</span><br><span class="line">key = [<span class="number">0x00000008</span>, <span class="number">0x00000001</span>, <span class="number">0x00000007</span>, <span class="number">0x00000001</span>, <span class="number">0x00000001</span>, <span class="number">0x00000000</span>, <span class="number">0x00000004</span>, <span class="number">0x00000008</span>, <span class="number">0x00000001</span>, <span class="number">0x00000002</span>, <span class="number">0x00000003</span>, <span class="number">0x00000009</span>, <span class="number">0x00000003</span>, <span class="number">0x00000008</span>, <span class="number">0x00000006</span>, <span class="number">0x00000006</span>, <span class="number">0x00000004</span>, <span class="number">0x00000008</span>, <span class="number">0x00000003</span>, <span class="number">0x00000005</span>, <span class="number">0x00000007</span>, <span class="number">0x00000008</span>, <span class="number">0x00000008</span>, <span class="number">0x00000007</span>, <span class="number">0x00000000</span>, <span class="number">0x00000009</span>, <span class="number">0x00000000</span>, <span class="number">0x00000002</span>, <span class="number">0x00000003</span>, <span class="number">0x00000004</span>, <span class="number">0x00000002</span>, <span class="number">0x00000003</span>, <span class="number">0x00000002</span>, <span class="number">0x00000005</span>, <span class="number">0x00000004</span>, <span class="number">0x00000000</span>, <span class="number">0x00000000</span>, <span class="number">0x00000000</span>, <span class="number">0x00000000</span>, <span class="number">0x00000000</span>]</span><br><span class="line">str1 = [<span class="number">0x0000007A</span>, <span class="number">0x000000CF</span>, <span class="number">0x0000008C</span>, <span class="number">0x00000095</span>, <span class="number">0x0000008E</span>, <span class="number">0x000000A8</span>, <span class="number">0x0000005F</span>, <span class="number">0x000000C9</span>, <span class="number">0x0000007A</span>, <span class="number">0x00000091</span>, <span class="number">0x00000088</span>, <span class="number">0x000000A7</span>, <span class="number">0x00000070</span>, <span class="number">0x000000C0</span>, <span class="number">0x0000007F</span>, <span class="number">0x00000089</span>, <span class="number">0x00000086</span>, <span class="number">0x00000093</span>, <span class="number">0x0000005F</span>, <span class="number">0x000000CF</span>, <span class="number">0x0000006E</span>, <span class="number">0x00000086</span>, <span class="number">0x00000085</span>, <span class="number">0x000000AD</span>, <span class="number">0x00000088</span>, <span class="number">0x000000D4</span>, <span class="number">0x000000A0</span>, <span class="number">0x000000A2</span>, <span class="number">0x00000098</span>, <span class="number">0x000000B3</span>, <span class="number">0x00000079</span>, <span class="number">0x000000C1</span>, <span class="number">0x0000007E</span>, <span class="number">0x0000007E</span>, <span class="number">0x00000077</span>, <span class="number">0x00000093</span>, <span class="number">0x00000000</span>, <span class="number">0x00000000</span>, <span class="number">0x00000000</span>, <span class="number">0x00000000</span>]</span><br><span class="line">str2 = [<span class="number">0x00000010</span>, <span class="number">0x00000008</span>, <span class="number">0x00000008</span>, <span class="number">0x0000000E</span>, <span class="number">0x00000006</span>, <span class="number">0x0000000B</span>, <span class="number">0x00000005</span>, <span class="number">0x00000017</span>, <span class="number">0x00000005</span>, <span class="number">0x0000000A</span>, <span class="number">0x0000000C</span>, <span class="number">0x00000017</span>, <span class="number">0x0000000E</span>, <span class="number">0x00000017</span>, <span class="number">0x00000013</span>, <span class="number">0x00000007</span>, <span class="number">0x00000008</span>, <span class="number">0x0000000A</span>, <span class="number">0x00000004</span>, <span class="number">0x0000000D</span>, <span class="number">0x00000016</span>, <span class="number">0x00000011</span>, <span class="number">0x0000000B</span>, <span class="number">0x00000016</span>, <span class="number">0x00000006</span>, <span class="number">0x0000000E</span>, <span class="number">0x00000002</span>, <span class="number">0x0000000B</span>, <span class="number">0x00000012</span>, <span class="number">0x00000009</span>, <span class="number">0x00000005</span>, <span class="number">0x00000008</span>, <span class="number">0x00000008</span>, <span class="number">0x0000000A</span>, <span class="number">0x00000010</span>, <span class="number">0x0000000D</span>]</span><br><span class="line"></span><br><span class="line">s = Solver()</span><br><span class="line"></span><br><span class="line">flag = [BitVec(<span class="string">'%d'</span> % i, <span class="number">8</span>) <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">36</span>)]</span><br><span class="line">flag1 = [<span class="number">0</span>]*<span class="number">36</span></span><br><span class="line">flag2 = [<span class="number">0</span>]*<span class="number">36</span></span><br><span class="line">str_1 = [<span class="number">0</span>]*<span class="number">36</span></span><br><span class="line">str_2 = [<span class="number">0</span>]*<span class="number">36</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">36</span>):</span><br><span class="line"> s.add(flag[i] < <span class="number">127</span>)</span><br><span class="line"> s.add(flag[i] > <span class="number">32</span>)</span><br><span class="line"></span><br><span class="line">flag1 = [(i >> <span class="number">4</span>) <span class="keyword">for</span> i <span class="keyword">in</span> flag]</span><br><span class="line">flag2 = [(i & <span class="number">0xf</span>) <span class="keyword">for</span> i <span class="keyword">in</span> flag]</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">6</span>):</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">6</span>):</span><br><span class="line"> <span class="keyword">for</span> k <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">6</span>):</span><br><span class="line"> str_1[<span class="number">6</span> * i + j] += flag1[<span class="number">6</span> * i + k] * key[<span class="number">6</span> * k + j]</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">6</span>):</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">6</span>):</span><br><span class="line"> str_2[<span class="number">6</span> * i + j] += flag2[<span class="number">6</span> * i + j] + key[<span class="number">6</span> * i + j]</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">36</span>):</span><br><span class="line"> s.add(str_1[i] == str1[i])</span><br><span class="line"> s.add(str_2[i] == str2[i])</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> s.check() == sat:</span><br><span class="line"> y = s.model()</span><br><span class="line"> flag_ = [<span class="built_in">chr</span>(y[flag[i]].as_long().real) <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">36</span>)]</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">''</span>.join(flag_))</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"Error!"</span>)</span><br></pre></td></tr></table></figure><h2 id="END"><a href="#END" class="headerlink" title="END"></a>END</h2><p>希望下次能自己写个出数据且不报错的z3(双手合十</p>]]></content>
<summary type="html"><h2 id="starts"><a href="#starts" class="headerlink" title="starts"></a>starts</h2><p>一直不会用z3,但是爆破里面经常会需要z3来一把梭,主要是在类型转换时里面经常有个a开头的类型搞我,给我整寄</summary>
<category term="0-1のpython" scheme="http://example.com/tags/0-1%E3%81%AEpython/"/>
</entry>
<entry>
<title>符号位扩展</title>
<link href="http://example.com/2021/12/12/movzx-movsz/"/>
<id>http://example.com/2021/12/12/movzx-movsz/</id>
<published>2021-12-12T07:24:34.000Z</published>
<updated>2021-12-12T14:15:32.632Z</updated>
<content type="html"><![CDATA[<h2 id="starts"><a href="#starts" class="headerlink" title="starts"></a>starts</h2><p>在做normal5的时候有遇到很多不会的地方,比如为什么要对数据按位与(0xff),补0扩展和符号位扩展有什么用,这些操作和数据的关联。其实类似于这个0xff在level7的时候已经遇到过一次,当时只知道是为了防止数据溢出,当我在对normal5最后flag的数据操作时发现ff的个数会影响最后得到的数据,且对数据的操作顺序改变会导致flag得到不是想要的数据。于是打算好好看一下这个问题。</p><h2 id="amp"><a href="#amp" class="headerlink" title="&"></a>&</h2><p>&上一个0xff的起因大概是用一个dword和byte进行了比较,提取数据的时候数据是这样的:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">0xFFFFFFC4, 0x00000034, 0x00000022, 0xFFFFFFB1, 0xFFFFFFD3, 0x00000011, 0xFFFFFF97, 0x00000007, 0xFFFFFFDB, 0x00000037, 0xFFFFFFC4, 0x00000006, 0x0000001D, 0xFFFFFFFC, 0x0000005B, 0xFFFFFFED, 0xFFFFFF98, 0xFFFFFFDF, 0xFFFFFF94, 0xFFFFFFD8, 0xFFFFFFB3, 0xFFFFFF84, 0xFFFFFFCC, 0x00000008</span><br></pre></td></tr></table></figure><p>询问了别人这个0xff是怎么回事,现在大概了解了一些,所谓的高位清零是什么意思。0xff转化为二进制数就是1111111,一共有8个bit,一个字节。&0xff就是使这个数字的低8bit不变,其他的全部清零,因为&的意思就是1&1为1,其他都是0。这样将这个数字&0xff就使低8bit这个byte是1就是1,是0就是0,把高位全部清零,从而可以限制到一个字节的大小。这样一来就可以进行比较了。</p><h2 id="movsx-movzx"><a href="#movsx-movzx" class="headerlink" title="movsx / movzx"></a>movsx / movzx</h2><p>MOVZX 指令(进行全零扩展并传送)将源操作数复制到目的操作数,并把目的操作数 0 扩展到 16 位或 32 位。这条指令只用于无符号整数。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">mov bx, 0A69Bh</span><br><span class="line">movzx eax, bx ;EAX = 0000A69Bh</span><br><span class="line">movzx edx, bl ;EDX = 0000009Bh</span><br><span class="line">movzx cx, bl ;CX = 009Bh</span><br></pre></td></tr></table></figure><p>MOVSX 指令(进行符号扩展并传送)将源操作数内容复制到目的操作数,并把目的操作数符号扩展到 16 位或 32 位。这条指令只用于有符号整数。(符号位就是0或者1)</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">byteVal BYTE 10001111b</span><br><span class="line">.code</span><br><span class="line">movsx ax,byteVal ;AX = 1111111110001111b</span><br></pre></td></tr></table></figure><p>看了别人对normal5的分析,这里对符号位进行扩展的原因是flag里面有负数。输出字符如果是负数那么就没办法转字符了。</p><p>去找了一下可以理解符号位扩展的文章,这个例子就比较容易理解:</p><p>以-64为例,其8位的二进制补码(1100 0000)表示成十六进制是0xC0,而等效的16位二进制补码(1111 1111 1100 0000)表示成十六进制是0xFFC0,很显然,位模式不一样。再看数+64,其8位二进制补码(0100 0000)和16位二进制补码(0000 0000 0100 0000)表示,分别是0x40与0x0040。事实是,扩展负数的大小与扩展非负数的大小是完全不同的。</p><p>处理不同长度的有符号数时,我们必须使用符号扩展。例如,将一个字节量与一个字量相加时,在相加之前,必须将字节量符号扩展到16位,其他运算可能需要符号扩展到32位。</p><p>清零和符号位扩展大多用于比较两个长度不同的数据。</p><h2 id="END"><a href="#END" class="headerlink" title="END"></a>END</h2><p>寄。</p>]]></content>
<summary type="html"><h2 id="starts"><a href="#starts" class="headerlink" title="starts"></a>starts</h2><p>在做normal5的时候有遇到很多不会的地方,比如为什么要对数据按位与(0xff),补0扩展和符号位扩展有什</summary>
<category term="0-1のpython" scheme="http://example.com/tags/0-1%E3%81%AEpython/"/>
</entry>
<entry>
<title>normal归纳</title>
<link href="http://example.com/2021/12/10/induction-1/"/>
<id>http://example.com/2021/12/10/induction-1/</id>
<published>2021-12-10T14:07:38.000Z</published>
<updated>2021-12-12T14:18:18.965Z</updated>
<content type="html"><![CDATA[<h2 id="starts"><a href="#starts" class="headerlink" title="starts"></a>starts</h2><p>在写normal3和4的时候感受到自己看题太不仔细了,normal3在最后调试答案的时候加了头和尾,一直显示flag错误,想了一想才知道这个是因为没有看清最后题目的输出。还是要把每道题都理解透彻自己反复思考去看怎么做,哪里自己没有注意到,好好去归纳总结一下。</p><h2 id="递归"><a href="#递归" class="headerlink" title="递归"></a>递归</h2><p>在normal3的时候遇到了递归算法,其实一开始想的是一个replace,感觉像是给flag的值用一个str的下标来替换,调试的时候一直在很混乱的循环,也没有想到递归这层,还是平常的基础知识运用的不够熟悉,遇到这些常见的算法都反应不过来。其实按照题目的意思是一个递归的排序。</p><p>递归算法简单来说就是一种调用自身函数的算法,递归必须有明确的结束条件,不然就是无止境的循环消耗电脑内存,可以说是利弊共存。</p><p>就题目里来说递归就是这样:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">data = <span class="number">0</span></span><br><span class="line">arr = []</span><br><span class="line">arr1 = []</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">fun</span>(<span class="params">a</span>):</span></span><br><span class="line"> <span class="keyword">global</span> data</span><br><span class="line"> <span class="keyword">global</span> arr</span><br><span class="line"> <span class="keyword">global</span> arr1</span><br><span class="line"> <span class="keyword">if</span>(a < <span class="number">64</span>):</span><br><span class="line"> arr.append(data)</span><br><span class="line"> arr1.append(a)</span><br><span class="line"> data = data + <span class="number">1</span></span><br><span class="line"> fun(<span class="number">2</span>*a + <span class="number">1</span>)</span><br><span class="line"> fun(<span class="number">2</span>*(a + <span class="number">1</span>))</span><br></pre></td></tr></table></figure><p>调用自身来进行运算</p><h2 id="hex与bytes"><a href="#hex与bytes" class="headerlink" title="hex与bytes"></a>hex与bytes</h2><p>又到了这个话题,上次写过一个hexstring和bytes的转化,写了很久,在normal4里面又碰到了这个问题。</p><img src="/2021/12/10/induction-1/1.png" class="" width="1"><img src="/2021/12/10/induction-1/2.png" class="" width="2"><p>在汇编窗口里你会发现这样的东西。<strong>byte ptr</strong>。这道题我没有调试,我直接照着伪代码逆了,结果错了,也没有想明白到底是为什么list会越界,也没有仔细去看汇编。从头再分析过来发现伪代码里的变量是被拆分了的,因为这里是把hex的字符串转成byte,然后以每两位写入。</p><img src="/2021/12/10/induction-1/3.png" class="" width="3"><p>有时候会遇到变量很多很难看,这时候就要反应过来看汇编和调试汇编了(我就没这么做就寄了),因为多个变量很有可能是组成一个地址的值或者字符,从而来replace这样,直接逆搞了好久也没有逆出东西来,一直在提示我越界。这道题其实就是一个replace,str2的下标是flag[i]的值的ascii码,只要索引str[i] ^ 0x19在str2里下标就可以了。</p><p>网上搜了一下是2018年湖湘杯的一道题,我看了爆破的脚本严重怀疑越界的可能性但应该别人出的脚本没有问题,等到有空考证了就补充上去。</p><p>果然是没问题的,自己脚本越界是因为提取的时候没有按byte提。。。爆破也可以,128个可显示字符来爆破。</p><p>在ida里有个&的字符在input前面,在这个地方是明显的取址字符,碰到的时候要注意。在复习数组识别的时候也有相同的提示,例如a[a+i<em>4],这里的a+i * 4是一个典型的整数数组的寻址,一个int为四个字节,是一个int指针,可以将类型修改成int</em>。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line">data1 = [0x32, 0x61, 0x34, 0x39, 0x66, 0x36, 0x39, 0x63, 0x33, 0x38, 0x33, 0x39, 0x35, 0x63, 0x64, 0x65, 0x39, 0x36, 0x64, 0x36, 0x64, 0x65, 0x39, 0x36, 0x64, 0x36, 0x66, 0x34, 0x65, 0x30, 0x32, 0x35, 0x34, 0x38, 0x34, 0x39, 0x35, 0x34, 0x64, 0x36, 0x31, 0x39, 0x35, 0x34, 0x34, 0x38, 0x64, 0x65, 0x66, 0x36, 0x65, 0x32, 0x64, 0x61, 0x64, 0x36, 0x37, 0x37, 0x38, 0x36, 0x65, 0x32, 0x31, 0x64, 0x35, 0x61, 0x64, 0x61, 0x65, 0x36, 0x00]</span><br><span class="line">data = [0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67,</span><br><span class="line"> 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47,</span><br><span class="line"> 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93,</span><br><span class="line"> 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31,</span><br><span class="line"> 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80,</span><br><span class="line"> 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A,</span><br><span class="line"> 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00,</span><br><span class="line"> 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58,</span><br><span class="line"> 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02,</span><br><span class="line"> 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38,</span><br><span class="line"> 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13,</span><br><span class="line"> 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19,</span><br><span class="line"> 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8,</span><br><span class="line"> 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24,</span><br><span class="line"> 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37,</span><br><span class="line"> 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE,</span><br><span class="line"> 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74,</span><br><span class="line"> 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6,</span><br><span class="line"> 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98,</span><br><span class="line"> 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28,</span><br><span class="line"> 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D,</span><br><span class="line"> 0x0F, 0xB0, 0x54, 0xBB, 0x16]</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def fun(i):</span><br><span class="line"> if(data1[i] < 48 | data1[i] > 57):</span><br><span class="line"> a = data1[i] - 87</span><br><span class="line"> else:</span><br><span class="line"> a = data1[i] - 48</span><br><span class="line"> a = a * 16</span><br><span class="line"> if(data1[i+1] < 48 | data1[i+1] > 57):</span><br><span class="line"> b = data1[i+1] - 87</span><br><span class="line"> else:</span><br><span class="line"> b = data1[i+1] - 48</span><br><span class="line"> return ((a + b) ^ 0x19)</span><br><span class="line"></span><br><span class="line">for i in range(35):</span><br><span class="line"> z = i</span><br><span class="line"> for m in range(128):</span><br><span class="line"> a = (m >> 4) % 16</span><br><span class="line"> b = (16 * m >> 4) % 16</span><br><span class="line"> j = 16 * a + b</span><br><span class="line"> k = fun(i*2)</span><br><span class="line"> if(data[j] == k):</span><br><span class="line"> print(chr(m),end="")</span><br></pre></td></tr></table></figure><h2 id="END"><a href="#END" class="headerlink" title="END"></a>END</h2><p>多归纳,,,不然会忘掉,,,</p>]]></content>
<summary type="html"><h2 id="starts"><a href="#starts" class="headerlink" title="starts"></a>starts</h2><p>在写normal3和4的时候感受到自己看题太不仔细了,normal3在最后调试答案的时候加了头和尾,一直显示</summary>
<category term="归纳" scheme="http://example.com/tags/%E5%BD%92%E7%BA%B3/"/>
</entry>
<entry>
<title>《逆向工程核心原理》-1</title>
<link href="http://example.com/2021/12/10/%E3%80%8A%E9%80%86%E5%90%91%E6%A0%B8%E5%BF%83%E5%8E%9F%E7%90%86%E3%80%8B-1/"/>
<id>http://example.com/2021/12/10/%E3%80%8A%E9%80%86%E5%90%91%E6%A0%B8%E5%BF%83%E5%8E%9F%E7%90%86%E3%80%8B-1/</id>
<published>2021-12-09T17:24:15.000Z</published>
<updated>2022-02-22T11:55:12.123Z</updated>
<content type="html"><![CDATA[<h2 id="starts"><a href="#starts" class="headerlink" title="starts"></a>starts</h2><p>《逆向工程核心原理》这本书是在todo list里最开头的,除了动手实践补充书上的知识也很重要,加班加点稍微写点笔记,让自己能看到些自己做了学了的东西吧。</p><h2 id="重要的"><a href="#重要的" class="headerlink" title="重要的"></a>重要的</h2><p>在开头书里写的是关于逆向工程。很重要的章节,告诉我要学什么,“嗯,先学这些概念吧,其他慢慢学”,不贪心,不急躁,希望自己也能体会到其中的乐趣,对生活和学习都热情以待吧。</p><p>前几章节主要讲了基本的调试程序和寄存器,但这些都是非常重要的部分,而我却一直记不住,写一些笔记来加深一下自己的印象。</p><h2 id="习惯"><a href="#习惯" class="headerlink" title="习惯"></a>习惯</h2><p>首先讲了调试一个简单的hello world的程序,但在调试中需要养成良好的习惯,使调试更加方便且看起来清楚。</p><p>1.学会添加注释和标签,书中示范的是od,但不论用什么调试软件,在需要的地方添加合适的注释都是需要养成的习惯。</p><p>2.在ida调试时需要对函数名称进行重命名,以方便自己的解读。进入函数看伪代码时可以通过快捷键来简化代码,或者根据分析重定义函数类型,这些在b站ida代码修复视频中有详细介绍。</p><p>暂时没有想到其他的,如果以后发现就补充上去。</p><h2 id="调试"><a href="#调试" class="headerlink" title="调试"></a>调试</h2><p>在书中介绍了四种调试hello world代码的方法,单步f8在代码量非常大的情况下是不可能使用的,一般来说我们会猜测并且设置断点,而在程序破解等实例中我们可以使用<strong>字符串检索法</strong>和<strong>API断点法</strong>来实现定位调用的函数。字符串检索在字符串被加密时也是不可行的,所以需要了解API的定义。</p><p>API是操作系统对用户应用程序提供的一系列函数,实现于xxx.dll文件。我们可以通过添加API断点来找出程序中调用函数的部分,从而找到关键代码。</p><h2 id="字节序"><a href="#字节序" class="headerlink" title="字节序"></a>字节序</h2><p>即大端序和小端序,BE与LE,分别采用正序和逆序的方式存储字节,大端序内存地址低位存储内存数据高位,内存地址高位位存储内存数据低位,而小端序则高存高,低存低,所以小端序是逆序输出,大端序为正序输出</p><h2 id="寄存器"><a href="#寄存器" class="headerlink" title="寄存器"></a>寄存器</h2><p>反复查看寄存器是调试中必不可少的部分,也是很吃耐心的一部分,通过了解不同寄存器的作用可以大大缩短调试的时间,更快的了解程序的运行过程和数据的变化。也是看汇编指令的基础。</p><p>以E开头的寄存器为32位,分别为EAX,EBX,ECX,EDX,ESI,EDI,EBP,ESP。是八个通用寄存器。</p><p>以S结尾的6个段寄存器分别为CS,DC,SS,ES,FS,GS,他们都是16位的。</p><p>还有EFLAGS(程序状态与控制寄存器)和EIP指令指针寄存器。(32位)</p><p>平常看的最多的是<strong>通用寄存器</strong>,用于传送和暂存数据。有些寄存器可以分为高低位的独立寄存器,例如EAX,有32位。AX是EAX的低16位,AH又是AX的高8位,AL是AX的低8位。在调试时可以根据需要使用的字节数来观察独立寄存器的变化。</p><p>EAX:累加器(数据) EBP:扩展基址指针寄存器(栈内数据指针)</p><p>EBX:基址寄存器(数据指针) ESI:源变址寄存器(字符串操作源指针)</p><p>ECX:计数器(字符串和循环操作) EDI:目的变址寄存器(字符串操作目标指针)</p><p>EDX:数据寄存器(I/O指针) ESP:栈指针寄存器(栈指针)</p><p>ESP与EBP相互协调作用,EBP暂存ESP的值,ESP为栈顶指针,最后得到的值返回ESP。</p><p><strong>段寄存器</strong>在这里没有详细的阐述,只是做了简单的介绍,等到后面了解了再记录。</p><p><strong>程序状态寄存器</strong>中我们常常会看到的指令大概时ZF,即运算结果为0则它的值为1,常用作判断指令,与cmp等指令连用,OF和CF都是溢出数据时返回1,OF为有符号数据,CF为无符号数据。</p><p><strong>指令指针寄存器</strong>最后的就是EIP,即为指令地址,在寄存器窗口点击EIP即可返回到当下执行的地方。</p><h2 id="END"><a href="#END" class="headerlink" title="END"></a>END</h2><p>其实看的内容比这些要多,这些都是基础但非常重要的知识,包括后面的栈和基础的汇编指令,但实在是太困了就先搁置下来,下次一起记录。</p><p>2021.12.10/02:25 晚安。</p>]]></content>
<summary type="html"><h2 id="starts"><a href="#starts" class="headerlink" title="starts"></a>starts</h2><p>《逆向工程核心原理》这本书是在todo list里最开头的,除了动手实践补充书上的知识也很重要,加班加点稍微</summary>
<category term="读书笔记-1" scheme="http://example.com/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0-1/"/>
</entry>
<entry>
<title>python字节流与字符串与aes解密函数</title>
<link href="http://example.com/2021/12/09/python%E5%AD%97%E8%8A%82%E6%B5%81%E4%B8%8E%E5%AD%97%E7%AC%A6%E4%B8%B2/"/>
<id>http://example.com/2021/12/09/python%E5%AD%97%E8%8A%82%E6%B5%81%E4%B8%8E%E5%AD%97%E7%AC%A6%E4%B8%B2/</id>
<published>2021-12-09T04:42:17.000Z</published>
<updated>2021-12-10T08:21:21.954Z</updated>
<content type="html"><![CDATA[<h2 id="starts"><a href="#starts" class="headerlink" title="starts"></a>starts</h2><p>最近在开始做normal系列的题目,前面了解过一些以后大体还是能够理解题目的意思,但在写脚本上面出现了很多困难,(代码力很重要),不会写脚本然后看了wp,结果wp是py2写的,会报错,语法也有一些不太一样的,让本就py很寄的我雪上加霜。。</p><p>上面的都是废话,主要写一写python字节流和字符串还有aes十分简便的带类型的解密。</p><h2 id="字节流与字符串"><a href="#字节流与字符串" class="headerlink" title="字节流与字符串"></a>字节流与字符串</h2><p>在写脚本的时候遇到了hexstring与bytes的转换问题,于是根据指点去查了一下字节流与字符串的使用和区别。以下是资料:</p><p>Python 3最重要的新特性之一是对字符串和二进制数据流做了明确的区分。文本总是Unicode,由str类型表示,二进制数据则由bytes类型表示。Python 3不会以任意隐式的方式混用str和bytes,你不能拼接字符串和字节流,也无法在字节流里搜索字符串(反之亦然),也不能将字符串传入参数为字节流的函数(反之亦然)。</p><p>意思就是,不能够在字符串中拼接和存放bytes类型的数据,而字节流可以看作c语言中的数组,是不能与str混用的。</p><h2 id="encode与decode"><a href="#encode与decode" class="headerlink" title="encode与decode"></a>encode与decode</h2><p>那如果需要将str与bytes转换,那么就需要用到encode()(编码)和decode()(解码)两种方法,实际就是编码与解码。这也是python少数比c语言麻烦的地方。在解码编码同时需要指明编码解码类型。编码和解码类型不一致会导致出现乱码。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">b = a.encode(<span class="string">'utf-8'</span>) <span class="comment">#用utf-8编码集将a字符串编码为字节数组</span></span><br><span class="line">b1 = b.decode(<span class="string">'utf-8'</span>) <span class="comment">#用utf-8编码集将变量b的字节数组解码成对应字符串</span></span><br></pre></td></tr></table></figure><p>如果不编码直接使用字符串来转换成bytes类型会报错。</p><img src="/2021/12/09/python%E5%AD%97%E8%8A%82%E6%B5%81%E4%B8%8E%E5%AD%97%E7%AC%A6%E4%B8%B2/1.jpg" class="" width="1"><p>也可以直接构造bytes类型数据</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">B = b"abcd"</span><br></pre></td></tr></table></figure><h2 id="二进制序列类型"><a href="#二进制序列类型" class="headerlink" title="二进制序列类型"></a>二进制序列类型</h2><p>bytes是不可变的二进制格式<strong>字节</strong>数据,而bytearray是可变的二进制数据,即可以对其进行操作来改变其中的数据。</p><p>在题目中遇到了hexstring转为bytes类型的问题,帮我改脚本的师傅用的是long_to_bytes,使用的模块是from Crypto.Util import number。当然byte_to_long也同样在模块里。(这个模块需要pip装)</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> Crypto.Util.number <span class="keyword">import</span> bytes_to_long, long_to_bytes </span><br><span class="line">a = long_to_bytes(<span class="number">0x934d8706bed74cd6eea683c7be86b2eb</span>)</span><br><span class="line"><span class="built_in">print</span>(a)</span><br><span class="line"><span class="comment">#结果为 b'\x93M\x87\x06\xbe\xd7L\xd6\xee\xa6\x83\xc7\xbe\x86\xb2\xeb'</span></span><br></pre></td></tr></table></figure><p>经过查资料,使用binascii.b2a_hex()也可以实现同样的效果:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> binascii</span><br><span class="line">a = binascii.a2b_hex(<span class="string">b'934d8706bed74cd6eea683c7be86b2eb'</span>)<span class="comment">#必须是bytes类型</span></span><br><span class="line"><span class="built_in">print</span>(a)</span><br><span class="line"><span class="comment">#结果为 b'\x93M\x87\x06\xbe\xd7L\xd6\xee\xa6\x83\xc7\xbe\x86\xb2\xeb'</span></span><br></pre></td></tr></table></figure><h2 id="AES解密函数(含aes类型)"><a href="#AES解密函数(含aes类型)" class="headerlink" title="AES解密函数(含aes类型)"></a>AES解密函数(含aes类型)</h2><p>在解决标准aes解密时,网上搜到的脚本大多数都是很多废话一大长串,实在是非常看不懂,(主要还是我菜),wp提供了一个非常简单且带有aes加密类型的解密(太好了!)于是我去了解了一下这个解密函数的用法</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> Crypto.Cipher <span class="keyword">import</span> AES</span><br><span class="line">aes = AES.new(key, AES.MODE_ECB) <span class="comment">#key为密钥</span></span><br><span class="line">flag = aes.decrypt(data) <span class="comment">#data是需要解密的内容</span></span><br></pre></td></tr></table></figure><p>这里的aes = AES.new(key, AES.MODE_ECB)中的ECB换成其他的类型也是成立的(<strong>CBC、ECB、CTR、OCF、CFB</strong>)</p><h2 id="END"><a href="#END" class="headerlink" title="END"></a>END</h2><p>弱类型我**&%¥%¥……¥#……,但是还要学……</p>]]></content>
<summary type="html"><h2 id="starts"><a href="#starts" class="headerlink" title="starts"></a>starts</h2><p>最近在开始做normal系列的题目,前面了解过一些以后大体还是能够理解题目的意思,但在写脚本上面出现了很多困</summary>
<category term="0-1のpython" scheme="http://example.com/tags/0-1%E3%81%AEpython/"/>
</entry>
<entry>
<title>python request</title>
<link href="http://example.com/2021/12/07/python-request/"/>
<id>http://example.com/2021/12/07/python-request/</id>
<published>2021-12-07T13:28:39.000Z</published>
<updated>2021-12-07T13:32:31.044Z</updated>
<content type="html"><![CDATA[<h2 id="start"><a href="#start" class="headerlink" title="start"></a>start</h2><p>在写模拟登录的时候需要用到python request模块,并且要抓包发包,只能说一无所知,甚至不知道url是什么。写一写给自己科普点网络常识,以方便听懂dalao们聊技术。</p><h3 id="所需要准备的包中的内容"><a href="#所需要准备的包中的内容" class="headerlink" title="所需要准备的包中的内容"></a>所需要准备的包中的内容</h3><p>url:意思是我们常称为的网址,例如:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">url = <span class="string">"https://baidu.com"</span></span><br></pre></td></tr></table></figure><p>user-agent:指用户代理,可以通过查看抓包的内容来看自己的user-agent,例如:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Mozilla/<span class="number">5.0</span> (Linux; Android <span class="number">10</span>; Pixel <span class="number">2</span> Build/QQ3A<span class="number">.200805</span><span class="number">.001</span>; wv) AppleWebKit/<span class="number">537.36</span> (KHTML, like Gecko) Version/<span class="number">4.0</span> Chrome/<span class="number">74.0</span><span class="number">.3729</span><span class="number">.186</span> Mobile Safari/<span class="number">537.36</span></span><br></pre></td></tr></table></figure><p>这些是请求头中的内容,可能需要用到的还有很多,用到了在学,寄(摆烂</p><p>Accept、Accept-Charset、Accept- Encoding、Accept-Language、Authorization、From、Host、If-Modified-Since、If-Match、If-None-Match、If-Range、If-Range、If-Unmodified-Since、Max-Forwards、Proxy-Authorization、Range、Referer、User-Agent</p><p>这一大堆都可能会用到</p><p>因为这次需要实行的是模拟登录,所以发包包内需要的内容是一些登录相关的数据,在这里需要使用python字典来实现。例如:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">login = {</span><br><span class="line"> <span class="string">"userName"</span>:<span class="string">"12345678901"</span>,</span><br><span class="line"> <span class="string">"app_id"</span>:<span class="string">"7"</span>,</span><br><span class="line"> <span class="string">"password"</span>:<span class="string">"c3l5czc5OTc=\n"</span></span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>准备工作做足了的话就可以开始写请求了)</p><h3 id="request-请求"><a href="#request-请求" class="headerlink" title="request 请求"></a>request 请求</h3><p>一般需要请求都是带参数的请求,get和post其实差距不是很大,从网上查了资料大概是这样的:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ hexo requests.get(url,params={<span class="string">"key1"</span>:<span class="string">"value1"</span>})</span><br><span class="line"> requests.post(url,data={<span class="string">"key1"</span>:<span class="string">"value1"</span>,<span class="string">"key2"</span>:<span class="string">"value2"</span>})</span><br><span class="line"> requests.post(url,json={<span class="string">"key1"</span>:<span class="string">"value1"</span>,<span class="string">"key2"</span>:<span class="string">"value2"</span>})</span><br></pre></td></tr></table></figure><p>如果写出来大概是这样,有请求头和respnse:(此处的body和my_header是定义的py字典)</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ hexo response = requests.post(url,params=body,headers=my_header)</span><br><span class="line"> <span class="built_in">print</span>(response.json)</span><br></pre></td></tr></table></figure><p>因为这里比较疑惑data和params有什么区别,通过资料了解到这是两种携带参数的方法。</p><p>简单来说,params是用来发送查询字符串,而data、json是用来发送正文的。<br>这两种参数post方法都可以用,get方法只能发查询字符串,不能发送正文。</p><p>params会将参数key、value拼接在url后;<br>json 表示使用application/json方式提交请求。接收方request.body的内容为’{“a”: 1, “b”: 2}’的这种形式;<br>data 表示使用application/form-urlencode方式提交请求,接收方request.body的内容为a=1&b=2的这种形式。</p><h3 id="需要注意的"><a href="#需要注意的" class="headerlink" title="需要注意的"></a>需要注意的</h3><p>其实请求里使用python字典要包括的东西很多(大概),第一次写也没完全了解大概需要去放些什么东西在请求头和包里,就抓到啥放啥)</p><p>请求头里可能还需要time out,accept之类的,补充一点互联网上捞到的看看。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">time_str = <span class="built_in">str</span>(<span class="built_in">int</span>(<span class="number">1000</span> * time.time()))</span><br><span class="line">key_dict = {</span><br><span class="line"> <span class="string">"source"</span>: <span class="string">"zh"</span>,</span><br><span class="line"> <span class="string">"target"</span>: <span class="string">"en"</span>,</span><br><span class="line"> <span class="string">"sourceText"</span>: <span class="string">"发送 POST 请求"</span>,</span><br><span class="line"> <span class="string">"sessionUuid "</span>: <span class="string">"translate_uuid"</span> + time_str</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><h3 id="END"><a href="#END" class="headerlink" title="END"></a>END</h3><p>摆烂人要为了自己兢兢业业捏</p><p>今天听的是RISE</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Target = <span class="string">'have fun and rise'</span></span><br><span class="line"><span class="built_in">print</span>(Target)</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h2 id="start"><a href="#start" class="headerlink" title="start"></a>start</h2><p>在写模拟登录的时候需要用到python request模块,并且要抓包发包,只能说一无所知,甚至不知道url是什么。</summary>
<category term="first" scheme="http://example.com/tags/first/"/>
</entry>
</feed>