-
Notifications
You must be signed in to change notification settings - Fork 0
/
local-search.xml
571 lines (270 loc) · 412 KB
/
local-search.xml
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
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>iotfuzz的思考</title>
<link href="/article/48b1ae2a.html"/>
<url>/article/48b1ae2a.html</url>
<content type="html"><![CDATA[<p>通过两年对iot设备的漏洞挖掘相关工作,我大概将iot的攻击面分成几点,web(即http协议),socker(自有协议),开源软件(三方协议),二进制软件。</p><h2 id="web"><a href="#web" class="headerlink" title="web"></a>web</h2><p>几乎能接触到的所有路由器设备,都会有一个web来管理路由器。这种通过嵌入式http服务来实现前后端与设备的交互,也是多数的iot被黑掉的第一入口。</p><h2 id="自有协议"><a href="#自有协议" class="headerlink" title="自有协议"></a>自有协议</h2><p>在研究摄像头时,其通过一个服务,监听了8822端口,通过udp协议连接之后,需要对其发送特定的命令来操作。</p><h2 id="开源软件"><a href="#开源软件" class="headerlink" title="开源软件"></a>开源软件</h2><p>像是ssh telnet dropbear,upnp等三方的软件或者提供三方协,mesh组网也一个可以研究的点。</p><h2 id="二进制软件"><a href="#二进制软件" class="headerlink" title="二进制软件"></a>二进制软件</h2><p>虽说上面三种都是由二进制编写而来,但像web可能会通过其他二进制文件来处理内容。</p><p>某个路由器的恢复配置功能会将配置文件上传到路由器,然后通过调用一个二进制程序来处理这个配置文件。</p><p>如果我们发现这个二进制程序的一个问题,然后通过构造配置文件,来绕过web端。</p><p>目前可远程攻击到的设备,基本攻击面就这几种。</p><p>除此之外就是usb等物理插口,侧信道攻击等,目前不在讨论范围。</p><p>二进制软件的fuzz还是以aflfuzz为主,协议fuzz的话,目前了解到比较多的还是boofuzz 支持多协议。</p><p>但boofuzz的库比较老,不知道还有没有替代品,又或者自研。</p><p>目前手上几款路由器,将对其在不同的fuzz情况下进行挖掘。在搜索对iotfuzz的可行性与性价比。</p>]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>tplink路由器http交互逻辑</title>
<link href="/article/1480780c.html"/>
<url>/article/1480780c.html</url>
<content type="html"><![CDATA[<p>tplink部分给予openwrt二开的系统,由/bin/dms文件负责http服务。</p><p>下面是一些交互逻辑</p><h2 id="regOprInterface函数的get方式"><a href="#regOprInterface函数的get方式" class="headerlink" title="regOprInterface函数的get方式"></a>regOprInterface函数的get方式</h2><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/image-20240110120026794.png" alt="image-20240110120026794"></p><p>类似这样的方式,其参数方式</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/image-20240110120123425.png" alt="image-20240110120123425"></p><p>method参数为get,参数为uri的第一位和第三位,类似这样</p><p>/hosts_info/info/cap_host_num</p><div class="code-wrapper"><pre><code class="hljs json"><span class="hljs-punctuation">{</span><span class="hljs-attr">"hosts_info"</span><span class="hljs-punctuation">:</span><span class="hljs-punctuation">{</span><span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span><span class="hljs-string">"cap_host_num"</span><span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span><span class="hljs-attr">"method"</span><span class="hljs-punctuation">:</span><span class="hljs-string">"get"</span><span class="hljs-punctuation">}</span></code></pre></div>]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title></title>
<link href="/article/0.html"/>
<url>/article/0.html</url>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>扬州慢·淮左名都</title>
<link href="/article/493c4167.html"/>
<url>/article/493c4167.html</url>
<content type="html"><![CDATA[<h1 id="《扬州慢·淮左名都》-姜夔"><a href="#《扬州慢·淮左名都》-姜夔" class="headerlink" title="《扬州慢·淮左名都》- 姜夔"></a>《扬州慢·淮左名都》- 姜夔</h1><p>淳熙丙申至日,予过维扬。夜雪初霁,荠麦弥望。入其城,则四顾萧条,寒水自碧,暮色渐起,戍角悲吟。予怀怆然,感慨今昔,因自度此曲。千岩老人以为有《黍离》之悲也。</p><p>淮左名都,竹西佳处,解鞍少驻初程。过春风十里,尽荠麦青青。自胡马窥江去后,废池乔木,犹厌言兵。渐黄昏,清角吹寒,都在空城。</p><p>杜郎俊赏,算而今重到须惊。纵豆蔻词工,青楼梦好,难赋深情。二十四桥仍在,波心荡,冷月无声。念桥边红药,年年知为谁生?</p>]]></content>
<categories>
<category>诗</category>
</categories>
</entry>
<entry>
<title>tplink企业vpn路由器GetShell</title>
<link href="/article/de04eab8.html"/>
<url>/article/de04eab8.html</url>
<content type="html"><![CDATA[<p>闲鱼上淘到某款企业vpn路由器,比较早的设备。</p><p>拿到某款设备肯定要想办法拿到固件来分析,并搞到getshell来干更多好玩的东西。</p><h2 id="前期尝试"><a href="#前期尝试" class="headerlink" title="前期尝试"></a>前期尝试</h2><p>通过官方网站下载的升级固件,尝试升级。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/image-20231113134757833.png" alt="image-20231113134757833"></p><p>寄!</p><p>尝试扫描端口查看是否开启ssh。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/image-20231113135348552.png" alt="image-20231113135348552"></p><p>寄!</p><p>都无效,也没有查到历史漏洞,只能拆了。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/IMG_6135.JPG" alt="IMG_6135"></p><p>串口通过调试,并不能获取到任何数据,可能是给关掉了。</p><p>基本思路均失败。</p><h2 id="发现配置文件,尝试新思路"><a href="#发现配置文件,尝试新思路" class="headerlink" title="发现配置文件,尝试新思路"></a>发现配置文件,尝试新思路</h2><p>在系统工具,设备管理中发现备份设置,该品牌设备多是基于openwrt开发,所以我们将希望寄托在备份文件中。</p><p>尝试下载备份文件。</p><p>分析发现为gzip压缩文件,直接解包。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/image-20231113140236875.png" alt="image-20231113140236875"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/image-20231113140453660.png" alt="image-20231113140453660"></p><p>发现了dropbear,passwd,shadow等文件,思路这不就来了。</p><p>首先尝试修改dropbear配置文件,将其改为开机自启。添加自定义用户,权限组为root,并设置其密码为自定义,方便dropbear打开后能正常登陆shell。</p><p>通过关键字搜索,发现dropbear配置文件</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/image-20231113141235260.png" alt="image-20231113141235260"></p><p>将ssh_port_switch修改为on,使设备启动时打开ssh</p><p>并记住其端口,33400</p><p>先将其打包恢复备份,查看是否有签名校验。</p><p>成功恢复,证明没有签名校验,然后尝试ssh连接设备</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/image-20231113142231336.png" alt="image-20231113142231336"></p><p>成功开启ssh,下一步就是创建自定义用户,是我们能够成功登入系统</p><p>修改passwd和shadow文件</p><p>修改passwd文件,这里我创建了一个与root一样的用户pipi</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/image-20231113142358252.png" alt="image-20231113142358252"></p><p>在shadow中给pipi用户设置密码,这里自定义即可,也可以直接复制自己linux机器的用户名密码</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/image-20231113142454495.png" alt="image-20231113142454495"></p><p>在次打包,将其恢复。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/image-20231113142620362.png" alt="image-20231113142620362"></p><p>成功登入,可以发现其就是一个openwrt。</p><p>cat /proc/cpuinfo后可以发现其设备为mips架构,使用的是高通骁龙QCA956X的一款芯片。</p><p>openwrt可玩性很高,这里不多赘述。</p><h2 id="提取固件"><a href="#提取固件" class="headerlink" title="提取固件"></a>提取固件</h2><p>getShell之后可以尝试使用dd命令来提取固件,大概思路如下。</p><p>使用cat /proc/mtd来查看分区</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/image-20231113143147532.png" alt="image-20231113143147532"></p><p>使用dd命令来直接提取分区</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/image-20231113143322534.png" alt="image-20231113143322534"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/image-20231113143411309.png" alt="image-20231113143411309"></p><p>得益于openwrt的各种命令都比较完整,可以用nc 等方式将固件下载到本地来进行分析。</p><p>以上就是通过修改备份文件的思路来GetShell。</p>]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>协议-upnp</title>
<link href="/article/697ff101.html"/>
<url>/article/697ff101.html</url>
<content type="html"><![CDATA[<p><strong>upnp访问过程</strong></p><p>#随笔</p><p>udp访问239.255.255.250的1900端口,ssdp协议</p><div class="code-wrapper"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<span class="hljs-keyword">import</span> reANY = <span class="hljs-string">"0.0.0.0"</span>DES_IP = <span class="hljs-string">"239.255.255.250"</span>PORT = <span class="hljs-number">1900</span>xml_str = <span class="hljs-string">b'M-SEARCH * HTTP/1.1\r\n'</span> \ \+ <span class="hljs-string">b'HOST: 239.255.255.250:1900\r\n'</span> \ \+ <span class="hljs-string">b'MAN: "ssdp:discover"\r\n'</span> \ \+ <span class="hljs-string">b'MX: 1\r\n'</span> \ \+ <span class="hljs-string">b'ST: urn:dial-multiscreen-org:service:dial:1\r\n'</span> \ \+ <span class="hljs-string">b'USER-AGENT: Google Chrome/87.0.4280.88 Windows\r\n\r\n\r\n'</span>s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,socket.IPPROTO_UDP)s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,<span class="hljs-number">1</span>)s.bind((ANY,PORT))s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, <span class="hljs-number">255</span>)s.setsockopt( socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(DES_IP) + socket.inet_aton(ANY))s.setblocking(<span class="hljs-literal">False</span>)s.sendto(xml_str,(DES_IP,PORT))<span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>: <span class="hljs-keyword">try</span>: data, address = s.recvfrom(<span class="hljs-number">2048</span>) <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e: <span class="hljs-keyword">pass</span> <span class="hljs-keyword">else</span>: <span class="hljs-built_in">print</span>(address) <span class="hljs-built_in">print</span>(data)</code></pre></div><p>通过这种方式可以获取到同网下的其他upnp设备信息</p><div class="code-wrapper"><pre><code class="hljs bash">(<span class="hljs-string">'10.0.0.1'</span>, 35150)b<span class="hljs-string">'NOTIFY * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nCACHE-CONTROL: max-age=3600\r\nLOCATION: http://10.0.0.1:56688/rootDesc.xml\r\nSERVER: OpenWRT/OpenWrt UPnP/1.1 MiniUPnPd/2.0\r\nNT: upnp:rootdevice\r\nUSN: uuid:97fd7581-d522-415d-bfae-a51ac69e4b55::upnp:rootdevice\r\nNTS: ssdp:alive\r\nOPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01\r\n01-NLS: 1693189369\r\nBOOTID.UPNP.ORG: 1693189369\r\nCONFIGID.UPNP.ORG: 1337\r\n\r\n'</span>(<span class="hljs-string">'10.0.0.1'</span>, 60956)b<span class="hljs-string">'NOTIFY * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nCACHE-CONTROL: max-age=1801\r\nNTS: ssdp:alive\r\nLOCATION: http://10.0.0.1:49153/wps_device.xml\r\nSERVER: Unspecified, UPnP/1.0, Unspecified\r\nNT: urn:schemas-wifialliance-org:service:WFAWLANConfig:1\r\nUSN: uuid:dd20a05f-a846-47cf-b976-047083022a1d::urn:schemas-wifialliance-org:service:WFAWLANConfig:1\r\n\r\n'</span></code></pre></div><p>现在是以10.0.0.1做演示</p><p>信息中能发现LOCATION</p><p><a href="http://10.0.0.1:49153/wps_device.xml"><em>http://10.0.0.1:49153/wps_device.xml</em></a></p><p><a href="http://10.0.0.1:56688/rootDesc.xml"><em>http://10.0.0.1:56688/rootDesc.xml</em></a></p><p>rootDesc.xml文件</p><p>This XML file does not appear to have any style information associated with it. The document tree is shown below.</p><div class="code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">root</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"urn:schemas-upnp-org:device-1-0"</span> <span class="hljs-attr">configId</span>=<span class="hljs-string">"1337"</span>></span> <span class="hljs-tag"><<span class="hljs-name">specVersion</span>></span> <span class="hljs-tag"><<span class="hljs-name">major</span>></span>1<span class="hljs-tag"></<span class="hljs-name">major</span>></span> <span class="hljs-tag"><<span class="hljs-name">minor</span>></span>1<span class="hljs-tag"></<span class="hljs-name">minor</span>></span> <span class="hljs-tag"></<span class="hljs-name">specVersion</span>></span> <span class="hljs-tag"><<span class="hljs-name">device</span>></span> <span class="hljs-tag"><<span class="hljs-name">deviceType</span>></span>urn:schemas-upnp-org:device:InternetGatewayDevice:1<span class="hljs-tag"></<span class="hljs-name">deviceType</span>></span> <span class="hljs-tag"><<span class="hljs-name">friendlyName</span>></span>RAX40 (Gateway)<span class="hljs-tag"></<span class="hljs-name">friendlyName</span>></span> <span class="hljs-tag"><<span class="hljs-name">manufacturer</span>></span>Netgear, Inc.<span class="hljs-tag"></<span class="hljs-name">manufacturer</span>></span> <span class="hljs-tag"><<span class="hljs-name">manufacturerURL</span>></span>http://www.NETGEAR.com<span class="hljs-tag"></<span class="hljs-name">manufacturerURL</span>></span> <span class="hljs-tag"><<span class="hljs-name">modelDescription</span>></span>OpenWRT router<span class="hljs-tag"></<span class="hljs-name">modelDescription</span>></span> <span class="hljs-tag"><<span class="hljs-name">modelName</span>></span>RAX40<span class="hljs-tag"></<span class="hljs-name">modelName</span>></span> <span class="hljs-tag"><<span class="hljs-name">modelNumber</span>></span>RAX40<span class="hljs-tag"></<span class="hljs-name">modelNumber</span>></span> <span class="hljs-tag"><<span class="hljs-name">modelURL</span>></span>http://www.netgear.com/home<span class="hljs-tag"></<span class="hljs-name">modelURL</span>></span> <span class="hljs-tag"><<span class="hljs-name">serialNumber</span>></span>5UP299WPA0C55<span class="hljs-tag"></<span class="hljs-name">serialNumber</span>></span> <span class="hljs-tag"><<span class="hljs-name">UDN</span>></span>uuid:97fd7581-d522-415d-bfae-a51ac69e4b55<span class="hljs-tag"></<span class="hljs-name">UDN</span>></span> <span class="hljs-tag"><<span class="hljs-name">serviceList</span>></span> <span class="hljs-tag"><<span class="hljs-name">service</span>></span> <span class="hljs-tag"><<span class="hljs-name">serviceType</span>></span>urn:schemas-upnp-org:service:Layer3Forwarding:1<span class="hljs-tag"></<span class="hljs-name">serviceType</span>></span> <span class="hljs-tag"><<span class="hljs-name">serviceId</span>></span>urn:upnp-org:serviceId:L3Forwarding1<span class="hljs-tag"></<span class="hljs-name">serviceId</span>></span> <span class="hljs-tag"><<span class="hljs-name">SCPDURL</span>></span>/L3F.xml<span class="hljs-tag"></<span class="hljs-name">SCPDURL</span>></span> <span class="hljs-tag"><<span class="hljs-name">controlURL</span>></span>/ctl/L3F<span class="hljs-tag"></<span class="hljs-name">controlURL</span>></span> <span class="hljs-tag"><<span class="hljs-name">eventSubURL</span>></span>/evt/L3F<span class="hljs-tag"></<span class="hljs-name">eventSubURL</span>></span> <span class="hljs-tag"></<span class="hljs-name">service</span>></span> <span class="hljs-tag"></<span class="hljs-name">serviceList</span>></span> <span class="hljs-tag"><<span class="hljs-name">deviceList</span>></span> <span class="hljs-tag"><<span class="hljs-name">device</span>></span> <span class="hljs-tag"><<span class="hljs-name">deviceType</span>></span>urn:schemas-upnp-org:device:WANDevice:1<span class="hljs-tag"></<span class="hljs-name">deviceType</span>></span> <span class="hljs-tag"><<span class="hljs-name">friendlyName</span>></span>WANDevice<span class="hljs-tag"></<span class="hljs-name">friendlyName</span>></span> <span class="hljs-tag"><<span class="hljs-name">manufacturer</span>></span>MiniUPnP<span class="hljs-tag"></<span class="hljs-name">manufacturer</span>></span> <span class="hljs-tag"><<span class="hljs-name">manufacturerURL</span>></span>http://miniupnp.free.fr/<span class="hljs-tag"></<span class="hljs-name">manufacturerURL</span>></span> <span class="hljs-tag"><<span class="hljs-name">modelDescription</span>></span>WAN Device<span class="hljs-tag"></<span class="hljs-name">modelDescription</span>></span> <span class="hljs-tag"><<span class="hljs-name">modelName</span>></span>WAN Device<span class="hljs-tag"></<span class="hljs-name">modelName</span>></span> <span class="hljs-tag"><<span class="hljs-name">modelNumber</span>></span>20220318<span class="hljs-tag"></<span class="hljs-name">modelNumber</span>></span> <span class="hljs-tag"><<span class="hljs-name">modelURL</span>></span>http://miniupnp.free.fr/<span class="hljs-tag"></<span class="hljs-name">modelURL</span>></span> <span class="hljs-tag"><<span class="hljs-name">serialNumber</span>></span>5UP299WPA0C55<span class="hljs-tag"></<span class="hljs-name">serialNumber</span>></span> <span class="hljs-tag"><<span class="hljs-name">UDN</span>></span>uuid:97fd7581-d522-415d-bfae-a51ac69e4b56<span class="hljs-tag"></<span class="hljs-name">UDN</span>></span> <span class="hljs-tag"><<span class="hljs-name">UPC</span>></span>000000000000<span class="hljs-tag"></<span class="hljs-name">UPC</span>></span> <span class="hljs-tag"><<span class="hljs-name">serviceList</span>></span> <span class="hljs-tag"><<span class="hljs-name">service</span>></span> <span class="hljs-tag"><<span class="hljs-name">serviceType</span>></span>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1<span class="hljs-tag"></<span class="hljs-name">serviceType</span>></span> <span class="hljs-tag"><<span class="hljs-name">serviceId</span>></span>urn:upnp-org:serviceId:WANCommonIFC1<span class="hljs-tag"></<span class="hljs-name">serviceId</span>></span> <span class="hljs-tag"><<span class="hljs-name">SCPDURL</span>></span>/WANCfg.xml<span class="hljs-tag"></<span class="hljs-name">SCPDURL</span>></span> <span class="hljs-tag"><<span class="hljs-name">controlURL</span>></span>/ctl/CmnIfCfg<span class="hljs-tag"></<span class="hljs-name">controlURL</span>></span> <span class="hljs-tag"><<span class="hljs-name">eventSubURL</span>></span>/evt/CmnIfCfg<span class="hljs-tag"></<span class="hljs-name">eventSubURL</span>></span> <span class="hljs-tag"></<span class="hljs-name">service</span>></span> <span class="hljs-tag"></<span class="hljs-name">serviceList</span>></span> <span class="hljs-tag"><<span class="hljs-name">deviceList</span>></span> <span class="hljs-tag"><<span class="hljs-name">device</span>></span> <span class="hljs-tag"><<span class="hljs-name">deviceType</span>></span>urn:schemas-upnp-org:device:WANConnectionDevice:1<span class="hljs-tag"></<span class="hljs-name">deviceType</span>></span> <span class="hljs-tag"><<span class="hljs-name">friendlyName</span>></span>WANConnectionDevice<span class="hljs-tag"></<span class="hljs-name">friendlyName</span>></span> <span class="hljs-tag"><<span class="hljs-name">manufacturer</span>></span>MiniUPnP<span class="hljs-tag"></<span class="hljs-name">manufacturer</span>></span> <span class="hljs-tag"><<span class="hljs-name">manufacturerURL</span>></span>http://miniupnp.free.fr/<span class="hljs-tag"></<span class="hljs-name">manufacturerURL</span>></span> <span class="hljs-tag"><<span class="hljs-name">modelDescription</span>></span>MiniUPnP daemon<span class="hljs-tag"></<span class="hljs-name">modelDescription</span>></span> <span class="hljs-tag"><<span class="hljs-name">modelName</span>></span>MiniUPnPd<span class="hljs-tag"></<span class="hljs-name">modelName</span>></span> <span class="hljs-tag"><<span class="hljs-name">modelNumber</span>></span>20220318<span class="hljs-tag"></<span class="hljs-name">modelNumber</span>></span> <span class="hljs-tag"><<span class="hljs-name">modelURL</span>></span>http://miniupnp.free.fr/<span class="hljs-tag"></<span class="hljs-name">modelURL</span>></span> <span class="hljs-tag"><<span class="hljs-name">serialNumber</span>></span>5UP299WPA0C55<span class="hljs-tag"></<span class="hljs-name">serialNumber</span>></span> <span class="hljs-tag"><<span class="hljs-name">UDN</span>></span>uuid:97fd7581-d522-415d-bfae-a51ac69e4b57<span class="hljs-tag"></<span class="hljs-name">UDN</span>></span> <span class="hljs-tag"><<span class="hljs-name">UPC</span>></span>000000000000<span class="hljs-tag"></<span class="hljs-name">UPC</span>></span> <span class="hljs-tag"><<span class="hljs-name">serviceList</span>></span> <span class="hljs-tag"><<span class="hljs-name">service</span>></span> <span class="hljs-tag"><<span class="hljs-name">serviceType</span>></span>urn:schemas-upnp-org:service:WANIPConnection:1<span class="hljs-tag"></<span class="hljs-name">serviceType</span>></span> <span class="hljs-tag"><<span class="hljs-name">serviceId</span>></span>urn:upnp-org:serviceId:WANIPConn1<span class="hljs-tag"></<span class="hljs-name">serviceId</span>></span> <span class="hljs-tag"><<span class="hljs-name">SCPDURL</span>></span>/WANIPCn.xml<span class="hljs-tag"></<span class="hljs-name">SCPDURL</span>></span> <span class="hljs-tag"><<span class="hljs-name">controlURL</span>></span>/ctl/IPConn<span class="hljs-tag"></<span class="hljs-name">controlURL</span>></span> <span class="hljs-tag"><<span class="hljs-name">eventSubURL</span>></span>/evt/IPConn<span class="hljs-tag"></<span class="hljs-name">eventSubURL</span>></span> <span class="hljs-tag"></<span class="hljs-name">service</span>></span> <span class="hljs-tag"></<span class="hljs-name">serviceList</span>></span> <span class="hljs-tag"></<span class="hljs-name">device</span>></span> <span class="hljs-tag"></<span class="hljs-name">deviceList</span>></span> <span class="hljs-tag"></<span class="hljs-name">device</span>></span> <span class="hljs-tag"></<span class="hljs-name">deviceList</span>></span> <span class="hljs-tag"><<span class="hljs-name">presentationURL</span>></span>http://www.routerlogin.net<span class="hljs-tag"></<span class="hljs-name">presentationURL</span>></span> <span class="hljs-tag"></<span class="hljs-name">device</span>></span><span class="hljs-tag"></<span class="hljs-name">root</span>></span></code></pre></div><p>其中可以获取设备名称制造商各种服务等信息</p><p>L3Forwarding1</p><div class="code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">service</span>></span><span class="hljs-tag"><<span class="hljs-name">serviceType</span>></span>urn:schemas-upnp-org:service:Layer3Forwarding:1<span class="hljs-tag"></<span class="hljs-name">serviceType</span>></span><span class="hljs-tag"><<span class="hljs-name">serviceId</span>></span>urn:upnp-org:serviceId:L3Forwarding1<span class="hljs-tag"></<span class="hljs-name">serviceId</span>></span><span class="hljs-tag"><<span class="hljs-name">SCPDURL</span>></span>/L3F.xml<span class="hljs-tag"></<span class="hljs-name">SCPDURL</span>></span><span class="hljs-tag"><<span class="hljs-name">controlURL</span>></span>/ctl/L3F<span class="hljs-tag"></<span class="hljs-name">controlURL</span>></span><span class="hljs-tag"><<span class="hljs-name">eventSubURL</span>></span>/evt/L3F<span class="hljs-tag"></<span class="hljs-name">eventSubURL</span>></span><span class="hljs-tag"></<span class="hljs-name">service</span>></span></code></pre></div><p>WANCommonIFC1</p><div class="code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">service</span>></span><span class="hljs-tag"><<span class="hljs-name">serviceType</span>></span>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1<span class="hljs-tag"></<span class="hljs-name">serviceType</span>></span><span class="hljs-tag"><<span class="hljs-name">serviceId</span>></span>urn:upnp-org:serviceId:WANCommonIFC1<span class="hljs-tag"></<span class="hljs-name">serviceId</span>></span><span class="hljs-tag"><<span class="hljs-name">SCPDURL</span>></span>/WANCfg.xml<span class="hljs-tag"></<span class="hljs-name">SCPDURL</span>></span><span class="hljs-tag"><<span class="hljs-name">controlURL</span>></span>/ctl/CmnIfCfg<span class="hljs-tag"></<span class="hljs-name">controlURL</span>></span><span class="hljs-tag"><<span class="hljs-name">eventSubURL</span>></span>/evt/CmnIfCfg<span class="hljs-tag"></<span class="hljs-name">eventSubURL</span>></span><span class="hljs-tag"></<span class="hljs-name">service</span>></span></code></pre></div><p>WANIPConn1</p><div class="code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">service</span>></span><span class="hljs-tag"><<span class="hljs-name">serviceType</span>></span>urn:schemas-upnp-org:service:WANIPConnection:1<span class="hljs-tag"></<span class="hljs-name">serviceType</span>></span><span class="hljs-tag"><<span class="hljs-name">serviceId</span>></span>urn:upnp-org:serviceId:WANIPConn1<span class="hljs-tag"></<span class="hljs-name">serviceId</span>></span><span class="hljs-tag"><<span class="hljs-name">SCPDURL</span>></span>/WANIPCn.xml<span class="hljs-tag"></<span class="hljs-name">SCPDURL</span>></span><span class="hljs-tag"><<span class="hljs-name">controlURL</span>></span>/ctl/IPConn<span class="hljs-tag"></<span class="hljs-name">controlURL</span>></span><span class="hljs-tag"><<span class="hljs-name">eventSubURL</span>></span>/evt/IPConn<span class="hljs-tag"></<span class="hljs-name">eventSubURL</span>></span><span class="hljs-tag"></<span class="hljs-name">service</span>></span></code></pre></div><p>通过访问SCPDURL可以获取服务的具体行为,以WANIPConn1为例</p><p>访问<a href="http://10.0.0.1:56688/WANIPCn.xml">http://10.0.0.1:56688/WANIPCn.xml</a></p><div class="code-wrapper"><pre><code class="hljs xml">This XML file does not appear to have any style information associated with it. The document tree isshown below.<span class="hljs-tag"><<span class="hljs-name">scpd</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"urn:schemas-upnp-org:service-1-0"</span>></span> <span class="hljs-tag"><<span class="hljs-name">specVersion</span>></span> <span class="hljs-tag"><<span class="hljs-name">major</span>></span>1<span class="hljs-tag"></<span class="hljs-name">major</span>></span> <span class="hljs-tag"><<span class="hljs-name">minor</span>></span>1<span class="hljs-tag"></<span class="hljs-name">minor</span>></span> <span class="hljs-tag"></<span class="hljs-name">specVersion</span>></span> <span class="hljs-tag"><<span class="hljs-name">actionList</span>></span> <span class="hljs-tag"><<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>SetConnectionType<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewConnectionType<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>ConnectionType<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"></<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"></<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>GetConnectionTypeInfo<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewConnectionType<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>ConnectionType<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewPossibleConnectionTypes<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>PossibleConnectionTypes<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"></<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"></<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>RequestConnection<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"></<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>ForceTermination<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"></<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>GetStatusInfo<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewConnectionStatus<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>ConnectionStatus<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewLastConnectionError<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>LastConnectionError<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewUptime<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>Uptime<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"></<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"></<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>GetNATRSIPStatus<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewRSIPAvailable<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>RSIPAvailable<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewNATEnabled<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>NATEnabled<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"></<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"></<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>GetGenericPortMappingEntry<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewPortMappingIndex<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>PortMappingNumberOfEntries<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewRemoteHost<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>RemoteHost<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewExternalPort<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>ExternalPort<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewProtocol<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>PortMappingProtocol<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewInternalPort<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>InternalPort<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewInternalClient<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>InternalClient<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewEnabled<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>PortMappingEnabled<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> </argument <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewPortMappingDescription<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>PortMappingDescription<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewLeaseDuration<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>PortMappingLeaseDuration<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"></<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"></<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>GetSpecificPortMappingEntry<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewRemoteHost<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in</direction <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>RemoteHost<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewExternalPort<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>ExternalPort<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewProtocol<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>PortMappingProtocol<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewInternalPort<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>InternalPort<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewInternalClient<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>InternalClient<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewEnabled<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>PortMappingEnabled<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewPortMappingDescription<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>PortMappingDescription<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewLeaseDuration<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>PortMappingLeaseDuration<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"></<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"></<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>AddPortMapping<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewRemoteHost<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>RemoteHost<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewExternalPort<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>ExternalPort<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewProtocol<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>PortMappingProtocol<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewInternalPort<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>InternalPort<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewInternalClient<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>InternalClient<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewEnabled<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>PortMappingEnabled<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewPortMappingDescription<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>PortMappingDescription<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewLeaseDuration<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>PortMappingLeaseDuration<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"></<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"></<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>DeletePortMapping<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewRemoteHost<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>RemoteHost<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewExternalPort<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>ExternalPort<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewProtocol<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>in<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>PortMappingProtocol<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"></<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"></<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">action</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>GetExternalIPAddress<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"><<span class="hljs-name">argument</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NewExternalIPAddress<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">direction</span>></span>out<span class="hljs-tag"></<span class="hljs-name">direction</span>></span> <span class="hljs-tag"><<span class="hljs-name">relatedStateVariable</span>></span>ExternalIPAddress<span class="hljs-tag"></<span class="hljs-name">relatedStateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">argument</span>></span> <span class="hljs-tag"></<span class="hljs-name">argumentList</span>></span> <span class="hljs-tag"></<span class="hljs-name">action</span>></span> <span class="hljs-tag"></<span class="hljs-name">actionList</span>></span> <span class="hljs-tag"><<span class="hljs-name">serviceStateTable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"no"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>ConnectionType<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>string<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"><<span class="hljs-name">defaultValue</span>></span>IP_Routed<span class="hljs-tag"></<span class="hljs-name">defaultValue</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"yes"</span></span><span class="hljs-tag"> <<span class="hljs-attr">name</span>></span>PossibleConnectionTypes<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>string<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValueList</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValue</span>></span>Unconfigured<span class="hljs-tag"></<span class="hljs-name">allowedValue</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValue</span>></span>IP_Routed<span class="hljs-tag"></<span class="hljs-name">allowedValue</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValue</span>></span>IP_Bridged<span class="hljs-tag"></<span class="hljs-name">allowedValue</span>></span> <span class="hljs-tag"></<span class="hljs-name">allowedValueList</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"yes"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>ConnectionStatus<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>string<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"><<span class="hljs-name">defaultValue</span>></span>Unconfigured<span class="hljs-tag"></<span class="hljs-name">defaultValue</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValueList</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValue</span>></span>Unconfigured<span class="hljs-tag"></<span class="hljs-name">allowedValue</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValue</span>></span>Connecting<span class="hljs-tag"></<span class="hljs-name">allowedValue</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValue</span>></span>Connected<span class="hljs-tag"></<span class="hljs-name">allowedValue</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValue</span>></span>PendingDisconnect<span class="hljs-tag"></<span class="hljs-name">allowedValue</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValue</span>></span>Disconnecting<span class="hljs-tag"></<span class="hljs-name">allowedValue</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValue</span>></span>Disconnected<span class="hljs-tag"></<span class="hljs-name">allowedValue</span>></span> <span class="hljs-tag"></<span class="hljs-name">allowedValueList</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"no"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>Uptime<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>ui4<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"no"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>LastConnectionError<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>string<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"><<span class="hljs-name">defaultValue</span>></span>ERROR_NONE<span class="hljs-tag"></<span class="hljs-name">defaultValue</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValueList</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValue</span>></span>ERROR_NONE<span class="hljs-tag"></<span class="hljs-name">allowedValue</span>></span> <span class="hljs-tag"></<span class="hljs-name">allowedValueList</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"no"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>RSIPAvailable<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>boolean<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"><<span class="hljs-name">defaultValue</span>></span>0<span class="hljs-tag"></<span class="hljs-name">defaultValue</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"no"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>NATEnabled<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>boolean<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"><<span class="hljs-name">defaultValue</span>></span>1<span class="hljs-tag"></<span class="hljs-name">defaultValue</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"yes"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>ExternalIPAddress<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>string<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"yes"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>PortMappingNumberOfEntries<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>ui2<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"no"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>PortMappingEnabled<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>boolean<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"no"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>PortMappingLeaseDuration<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>ui4<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"><<span class="hljs-name">defaultValue</span>></span>3600<span class="hljs-tag"></<span class="hljs-name">defaultValue</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValueRange</span>></span> <span class="hljs-tag"><<span class="hljs-name">minimum</span>></span>0<span class="hljs-tag"></<span class="hljs-name">minimum</span>></span> <span class="hljs-tag"><<span class="hljs-name">maximum</span>></span>604800<span class="hljs-tag"></<span class="hljs-name">maximum</span>></span> <span class="hljs-tag"></<span class="hljs-name">allowedValueRange</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"no"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>RemoteHost<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>string<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"no"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>ExternalPort<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>ui2<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"no"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>InternalPort<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>ui2<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValueRange</span>></span> <span class="hljs-tag"><<span class="hljs-name">minimum</span>></span>1<span class="hljs-tag"></<span class="hljs-name">minimum</span>></span> <span class="hljs-tag"><<span class="hljs-name">maximum</span>></span>65535<span class="hljs-tag"></<span class="hljs-name">maximum</span>></span> <span class="hljs-tag"></<span class="hljs-name">allowedValueRange</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"no"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>PortMappingProtocol<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>string<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValueList</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValue</span>></span>TCP<span class="hljs-tag"></<span class="hljs-name">allowedValue</span>></span> <span class="hljs-tag"><<span class="hljs-name">allowedValue</span>></span>UDP<span class="hljs-tag"></<span class="hljs-name">allowedValue</span>></span> <span class="hljs-tag"></<span class="hljs-name">allowedValueList</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"no"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>InternalClient<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>string<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"><<span class="hljs-name">stateVariable</span> <span class="hljs-attr">sendEvents</span>=<span class="hljs-string">"no"</span>></span> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>PortMappingDescription<span class="hljs-tag"></<span class="hljs-name">name</span>></span> <span class="hljs-tag"><<span class="hljs-name">dataType</span>></span>string<span class="hljs-tag"></<span class="hljs-name">dataType</span>></span> <span class="hljs-tag"></<span class="hljs-name">stateVariable</span>></span> <span class="hljs-tag"></<span class="hljs-name">serviceStateTable</span>></span><span class="hljs-tag"></<span class="hljs-name">scpd</span>></span></code></pre></div><p>分类统计有以下几种:</p><p>SetConnectionType,GetConnectionTypeInfo,RequestConnection,ForceTermination,GetStatusInfo,GetNATRSIPStatus,GetGenericPortMappingEntry,GetSpecificPortMappingEntry,AddPortMapping,DeletePortMapping,GetExternalIPAddress</p><p>通过构造POST请求,访问controlURL:<a href="http://10.0.0.1:56688/ctl/IPConn">http://10.0.0.1:56688/ctl/IPConn</a></p><div class="code-wrapper"><pre><code class="hljs http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/ctl/IPConn</span> <span class="hljs-meta">HTTP/1.1</span><span class="hljs-attribute">Host</span><span class="hljs-punctuation">: </span>10.0.0.1:56688<span class="hljs-attribute">Upgrade-Insecure-Requests</span><span class="hljs-punctuation">: </span>1<span class="hljs-attribute">User-Agent</span><span class="hljs-punctuation">: </span>Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.62<span class="hljs-attribute">Accept</span><span class="hljs-punctuation">: </span>text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7<span class="hljs-attribute">Accept-Encoding</span><span class="hljs-punctuation">: </span>gzip, deflate<span class="hljs-attribute">Accept-Language</span><span class="hljs-punctuation">: </span>zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6<span class="hljs-attribute">SOAPAction</span><span class="hljs-punctuation">: </span>"urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress"<span class="hljs-attribute">Connection</span><span class="hljs-punctuation">: </span>close<span class="hljs-attribute">Content-Length</span><span class="hljs-punctuation">: </span>260<span class="language-vim"><<span class="hljs-variable">s:Envelope</span> xmln<span class="hljs-variable">s:s</span>=<span class="hljs-string">"http://schemas.xmlsoap.org/soap/envelope/"</span> <span class="hljs-variable">s:encodingStyle</span>=<span class="hljs-string">"http://schemas.xmlsoap.org/soap/encoding/"</span>></span><span class="language-vim"><<span class="hljs-variable">s:Body</span>></span><span class="language-vim"><<span class="hljs-keyword">u</span>:GetExternalIPAddress xmln<span class="hljs-variable">s:u</span>=<span class="hljs-string">"urn:schemas-upnp-org:service:WANIPConnection:1"</span>></span><span class="language-vim"></<span class="hljs-keyword">u</span>:GetExternalIPAddress></span><span class="language-vim"></<span class="hljs-variable">s:Body</span>></span><span class="language-vim"></<span class="hljs-variable">s:Envelope</span>></span></code></pre></div><p>重要的有head中的SOAPAction,构造方式为serviceType#action即:urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress</p><p>post参数来源action中的direction为in的参数,如果只有out参数,即可不用构造post参数,直接获取。</p><p>in参数的数据类型在serviceStateTable中可以获取</p><div class="code-wrapper"><pre><code class="hljs http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/ctl/IPConn</span> <span class="hljs-meta">HTTP/1.1</span><span class="hljs-attribute">Accept-Encoding</span><span class="hljs-punctuation">: </span>identity<span class="hljs-attribute">User-Agent</span><span class="hljs-punctuation">: </span>Python-urllib/3.11<span class="hljs-attribute">Host</span><span class="hljs-punctuation">: </span>10.0.0.1:56688<span class="hljs-attribute">Content-Length</span><span class="hljs-punctuation">: </span>358<span class="hljs-attribute">Content-Type</span><span class="hljs-punctuation">: </span>text/xml; charset="utf-8"<span class="hljs-attribute">Soapaction</span><span class="hljs-punctuation">: </span>"urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping"<span class="hljs-attribute">Connection</span><span class="hljs-punctuation">: </span>close<span class="language-xml"></span><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">s:Envelope</span> <span class="hljs-attr">xmlns:s</span>=<span class="hljs-string">"http://schemas.xmlsoap.org/soap/envelope/"</span> <span class="hljs-attr">s:encodingStyle</span>=<span class="hljs-string">"http://schemas.xmlsoap.org/soap/encoding/"</span>></span></span><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">s:Body</span>></span></span><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">u:DeletePortMapping</span> <span class="hljs-attr">xmlns:u</span>=<span class="hljs-string">"urn:schemas-upnp-org:service:WANIPConnection:1"</span>></span></span><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">NewRemoteHost</span>></span>AAAA<span class="hljs-tag"></<span class="hljs-name">NewRemoteHost</span>></span></span><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">NewExternalPort</span>></span>AAAA<span class="hljs-tag"></<span class="hljs-name">NewExternalPort</span>></span></span><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">NewProtocol</span>></span>TCP<span class="hljs-tag"></<span class="hljs-name">NewProtocol</span>></span></span><span class="language-xml"><span class="hljs-tag"></<span class="hljs-name">u:DeletePortMapping</span>></span></span><span class="language-xml"><span class="hljs-tag"></<span class="hljs-name">s:Body</span>></span></span><span class="language-xml"><span class="hljs-tag"></<span class="hljs-name">s:Envelope</span>></span></span></code></pre></div><p>通过gdb调试可以发现,可以获取到</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/image-20230829175431203.png" alt="image-20230829175431203"></p><p>python中又个upnpy库,可以很方便的执行上述步骤。</p><div class="code-wrapper"><pre><code class="hljs bash">python3 -m pip install upnpy</code></pre></div><p>使用方式</p><div class="code-wrapper"><pre><code class="hljs python"><span class="hljs-keyword">import</span> upnpy\<span class="hljs-comment">#获取upnp</span>upnp = upnpy.UPnP()\<span class="hljs-comment">#扫描,返回一个设备列表</span>devices = upnp.discover()\<span class="hljs-comment">#确定设备,两种方式都可以</span>devide = devices[<span class="hljs-number">0</span>]device = upnp.get_igd()\<span class="hljs-comment">#获取服务列表</span>services = device.get_services()\<span class="hljs-comment">#确定服务,同两种方式均可</span>service = services[<span class="hljs-number">0</span>] service = device[<span class="hljs-string">'WANPPPConnection.1'</span>] <span class="hljs-comment">#service id</span>\<span class="hljs-comment">#获取服务的actions,返回一个action列表</span>service.get_actions()\<span class="hljs-comment">#通过service.action['name']()可以执行</span>service.GetExternalIPAddress() <span class="hljs-comment">#{'NewExternalIPAddress': '10.100.40.182'}</span>\<span class="hljs-comment">#通过service.action['name'].get_input_arguments()可以获取参数</span>service.DeletePortMapping.get_input_arguments()\<span class="hljs-comment">#[{'name': 'NewRemoteHost', 'data_type': 'string', 'allowed_value_list': []}, {'name': 'NewExternalPort', 'data_type': 'ui2', 'allowed_value_list': []}, {'name': 'NewProtocol', 'data_type': 'string', 'allowed_value_list': ['TCP', 'UDP']}]</span>\<span class="hljs-comment">#发送服务</span>service.AddPortMapping( NewRemoteHost=<span class="hljs-string">''</span>, NewExternalPort=<span class="hljs-number">80</span>, NewProtocol=<span class="hljs-string">'TCP'</span>, NewInternalPort=<span class="hljs-number">8000</span>, NewInternalClient=<span class="hljs-string">'192.168.1.3'</span>, NewEnabled=<span class="hljs-number">1</span>, NewPortMappingDescription=<span class="hljs-string">'Test port mapping entry from UPnPy.'</span>, NewLeaseDuration=<span class="hljs-number">0</span>)</code></pre></div>]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>tenda交换机TEG5328F</title>
<link href="/article/5e04fdd4.html"/>
<url>/article/5e04fdd4.html</url>
<content type="html"><![CDATA[<div class="hbe hbe-container" id="hexo-blog-encrypt" data-wpm="Oh, this is an invalid password. Check and try again, please." data-whm="OOPS, these decrypted content may changed, but you can still have a look."> <script id="hbeData" type="hbeData" data-hmacdigest="fd5a740968d8ebb1aeb5617d5a097ebd04473b1be6c0b86249a45ee710651525">47d9635aef24c3f077639ffda1f136d75037d67898e100ef3e39b7bff681bd87f245aa5d7196c431703df7cc16624b709b6ebbbe3486dc92879b5be284aafc7c16cd693c1abba4194b36523de8f1f9eac27356f6c1755e9cddd0fae08e1d9de7bbd023b8c426c6a633f2ef3b2e4952b88915f546110026e4c89a273dac34c73d4ee409be8e1dadcdb2de2bbe23b4db9c7dc6540410b0738c2ec8c907aaf79e725fab3e9508be4706d4a5026603ecd46c7deaffe67668c566c47b8361f040e59bc809f015176b9710e9f71fa21206bb6dc4ad5df74ff2de008d99b1962e434f10733ede2e1cd2e0ab14a604638ff6ae6cae7cf5de4e41129ba5757ae49dd454f7f391c5e630ce6aa077d8f2e4bed7e0da91b2f4653fd342c6d64cb828032e7d32595c65fc6fa315f4fd2e8df66266f391939ebfc1f62f2c8c5af1c6dcafc05fca2215d71c2fe7be688c2f388914dbccad1794c775499a7e247526b6f3122c3a9f617ddbb613769b765393f4d1a87f5e20e169ea1613a15b755f78e5a3d4663c31b6ddfe2e86607433ecbb175e44da836938d262e969d200d3b789a05d60f5e58df95958a31e667c6631d8797f321630317d79d3b43fb1e6790909e9c8d70038b6a5eb87a437b1df9bd8ac3a6d13e11240f8f924d98af7146103c518aea03a05ce004345d6246800a408c96782a4586b6aa7eda864a27483104c2c9fa7d24e7b14400a4f76f8e6b611877187fcadff003fae3613d8c868d1a38595d26d96026451e46e6de70962f552c98c6fc1100169950bba27cb9834b1f42056230b1348ef773b3a5c4b07985a5f15fd6082d6ab09bcbc21793d6d866f6de503df5a3efd15a172cefa0fb43e624f5733ac493b5c592ddcc508685dd00c006adaa48bcb921f3f8b17259b6a7773de3aa996eddc4e38f395f6b97e50b17de8ee06ad940f62b4170af97a1d77d52b6f1c54a8fcef9234c41842113388ebf205b7ebb196c9341fd2a281c63a38b309b2d1cc48fbaf5d441aa28000749c3312e18b69e842e6419c2dbf957987add92fa796132e505ff0fe37182dd031e8fea7905e53c2963a52f7eb83681d55f5b54daf79342a98acf4840e29065f4a0ab8fc32c6e600d33ea2fd9e15cb701a9741304eb303754d705de1cd524e1ab63ca77d216d711df5b3ecaec27beeecdd13c4d7ad60599717882268e53bb10f4beb1877f4702e906f3f63887b38ba5966fb7f0408b61b7daed17116a9c3a94f4c8cdb5b434cf412416a895c75dd97a0301f8ca5c6c4a57f7c33514a004a42f5e1ec2b1dcdadcd93e186ed570f0625cffb98879267f35ac6701d8df48b31a1716d504be88a95873eba9784c3dce2bd02e6c96f64077e783d80aeaeb5be1c42a8aea747b98f97ac60166f9026e370614b85f40a74bcb2e4706660c0a71dccfbecc5ee2c36373824dec48dffb58df5fc69f4078b2bc3f6fe0b9e61d541a7792b8cbef86468e5faad02aca39c0c9d128c0816212a1e28384ddf4de95b785dde97a63b9f9d68c4ddcaa9c280c1205b6f5bbd53a9ddf5775e889cf03984d53779ed09417f8459a32d6f416e7e858de772a52511b65513f6311153da3daa99b6ab816086f649e30e1596368b6813200e19d1f6b7efd7ba2de824731857bfd444bae318bd1cd39e948016838f884e2e3531068b43284895c71082c7ad2b7b817a98d93f7311b13e5bb6b1d3e9929d3e8b1e5c6e36ea3508fc0b349c877d64c217946b7fc9a3c235697ccd82b7d126adb9de3a3b43e5d5492369c542f1822832df27db90a70144d4c57cf7fb952aa979abba1b601083649ca9fdb13794ac3ef87e7f7c6304e5730dfbc08c8d43e2a567bf24878e14c3ae863c97ee39d4b5903e6424cb0f7c7b5b0f35440c16f49dc5d926118255f762a6a87370e9ba804a49a006bbbef0db4b00576a1fc618b4a510cbd99540d682a865c8457d48a021618792857a2e15c01c02c26b9117462073c171f357ed5141611776b636869dea3420a400bae73e07004307077196d10dcea8087962b9233d927aa90b52051655ad94bbb26ebb8d3b30fd659a0164573c4f8b5d4333dec205873686e5cc3c3fd66c452110ad9e365412cc3efeabc7169fd90e93d0fdcab70b1ac7ea0368c8b4efecca0ace0e522122fe6ead27820ac14f5b1528af936c48fbdcc4cedad341297b188eab34ba43d736818873ca7dd0bbae74e102f38c34c65c69e19ad23be69774d7a7e910546097984a09f86b9fc28ba43fc9ab8e7b95def021ee03eaebe145c9367a0515a9f1340d5c13e844bbf008d61561958f5dc705ab1ce9f3c9faa313555d46889d55377770db6575c7518e4a25437d162695b3dd1a7f7f53923c836b19af5749bcd0bfe937fe42da3d7e6bfd393539d2edc1af5f5d2ea082306d328427923b81dba2cd7e94ff590d75e695ffef2ec1c33b525fbfe108a5a0fdd961d21a93fcfd9de7dd25bdf04f52958fc119cee06afac8cd5ae02d937a3d249d767754f640a8c8874f4fd0d914404d85fdf63f5e3ac7c5e6669dc8d4fa41f92dc98a415846ce3bd09c9c063b8cfd8e1b44ff51593f172df8bc7ac923d81889add6288be91d2315afff2d7c873a7140b398a1375795bcd610719add9d5602e0bd4449689ddbe1fbfe22202fc7f428c809f8787e6f51f5e18cef5332a3e4fde0a300d0de89832773513f2e295e916d071dbebb64b91097568783aea060121adaa2f5bf28811a8f17bfa119bc91c90b58dc9eb27376b9b2a72267b518b4da41689dd9a7f7bd9c39d73a2c33b6eef1d75de053ef15259f84a5fefc07029efee383c27257a8841c0f858f848eb94114d05169f226b8c9c19aaf8c818162df85770876a12628c14c555af96342a16bd97e5318bc9329994509c6823d19e7dc12d91324275e241bbf4105ecf26c1b196a115fa155a2710cce382e93db9b93ed84600289449cca51751ce46d4f1af3b2c346f447530e8f9c2327f5565f4ab615e7e0f8137291aeb04e5058dacbf6585508c74410ca0d3fc9bda00d762f40c4743db8dddf5816cf6185199de746334f6f9ef57ec17f0839e388911b9d8833fe6610a0df3ab8fa58b781ac934730e49dbe2ccbd00ea203fb69f4c58ab14622c81c18e5088e9dfd670ec54cfc749bed0cd8d081e2ef704e415c730ba2ecba1a2b974e70f3f6889cda3d0c5e4c9fd9e00633f95335e4bdc6be80ce144374a6554e06219dff4a46c09befb683b1f44f647c04341e1739bc8a2e2a782408a6a478d51e7cd4d92874e1dce1c9f8fb2163269a109a29377c5974ed6485d23c98f6967ac088d6c8edb75ddc153712ef7a9511f7b86577a9b3c0e514eb5f522c86e60d156c836c918ea3df8f561842589715f509d10bc16a3f51774320846bd263f94e49ce07f562c95c357e05626ebd935648621b000b73b298ff7f9beda9266131471517d5b0f51cd3560b806e799975721a59e925f66a28ed1bbebe393500df41b800dbafd7703b06679d7daf481e4e61d59940310100960aeacb1425e9263bbd734e5b33974f99b4e067fc845b342ad9918ae606bba6800e12520b394c7dfc487bc2ef70ffa63d876eee2688dbd0a6b158398e611bbaa2d2c992637c476f20d19194c3498c69d2d457ee768f80ee2af7443eb348f80dd5d3f2559dd86967483fc8b22b4a1b39e44f47b46696c1f80e929d0466330ae84a2cf8464f018eeb87fc0331eaa59ff44d82dd95443cc1513c7ff2130aa30dfe6bef2e5206c53c6fb072902bfe1fc63d2f4ea803eb6a36c301868dec57eaa1b399534a59fe1d2f54315d68657cf360fb9cc1611ac8f18fab2e0f3a003927a817234f254eff2e91f6071d266fd5cfdc3ce26ab3b295a3c555a392dc713e3d786165940f1556dbe4c24d155f6213a4afc9c3201548e31ca5c5dffc76a01967846457b6c7b85f22445166bb012c6f1865bf9739043a17b879cfcd01ca8ba0f61ab3aa0556109208f1d935a0297ea809f3ab5cac41b68e3e1f3ba4c25d49712e75fd5feb58c3ab6772f450860e5be439e5f54f8cf386f5155712584ad9ffdcde642fa6c714a34f91b55f236c13a3cad37a5dfcef21e5711f44f3af11cdaea002e60f16ac1a97fcd3da1cec2228eabd98ed7e40f68d657d5e364f055341d0f77f9328269a741ad5c76d68cb134c566adfb3729d5aa3b08d2fae3f194712f67d4fbb59fa991b9eb94b31725fe3c2832c4a0c957add17d3d551f39f41166515421d7ae8058c0fc8121ba4f84622fb4337a35e17ddcf1d8a7d8320ac1e306a9c1ca17ba2b8acf2f7b835acfe79fcc099444fee05b1cb5ecb94087eadc37ed2c42444fde19bda3d9d84f9477dd3a8983030b250b9aa013291e97036f12634c5cd57c96c34997b8b1133a7d77bcebd0847a1775bae0837078ca6fbe460b0aa77c8d90eb81045df3ac9065e71b86f3896605f41b6814a57a8942285ee5be54b7610d5d9bd98c3c90c5b87f806c933d2088490efc2da083e8cc4a4b24e9d1b0686118b36d1719ee1f5bae113786066970213831d4671f35e87cf818cba85c4c40732cab217ef3e7f8c77a61cfa5257257157f5f7050be587de9c3a2b3468e9b2ef4da207e26497ea6d1e381286a4590a526a3209dbca2b894739504a15eb38332bfce2c2d780fbfacfa54b9ffb2b12703b71a7fb60dbc00c4254da920101b44687b2031834ab2cde6abd3dedc939e8e41d7ea92e8e490387120d15fd5e555e6931b37f74027f3d971c07e4e283e03771b6451dfcf26ef0bcaf7f080af69904ec0e027f7e8a3100dbe8ca2f0a246077ced6f4b73cd86ba6e7d1118754e04177d72db39c6513ffa313ab91502afe866c795ab3dd4beb90ee46280c8b026df04b076f5b5a1ce53e30675a5c2aa3e8f694bfdefc020d05bcba5e253707a0ebaa73d92e8aef06bf55c6715bfe20eecad23176234744311111e3771942630bf1e526af0e94816a6f36022898502c71428e81b3e9b2aeff966685dd7e56862abcd4901549772387a76e54651c95d5004b35873988cff2c0a88b895c9a86a34854c29a5bd4b64f5e1113d6077987a097674a7245b38cf21ac82a330126f4f710a50a5bac120451d28783d8b2589cf2e08ad78b3f940057035635c5ae628f923ad8753cfeadffc55da535166146fd975ed913ed7a5c9d234ba7a615a319e64409e44af689dd36012751be9d7f6f0e49eddec557aee40999eee0fc66006961a3b36e9332cff0f7531bd7192c393a7e8e1b78b84db808737ee20f467e223667339408e7d4c1cb6693dbb3b71dba0e08a0aae9158dbe21a3b4e2160a81a0416c4466a6856205a1f0c1bb7e5bcf2efcf9ebc6bc87f6dcd5e7f93ee959f15cbb2e069739400d74f53ff0a6f4492a844ea25364dc43b2e726f56f2d49baac7e13a8051f6f893cfd983759e9335f536712114669d9a28a5cd8e424ab1389b4f57e149c799b0039824218ecb727d31d81bc900918204b6e4d373d5d311d8fcf7e07beadd039995380ca81314402bf45ea3621c2f277f196ba07446040533aa886ee4724cc430e3bcef77f26aa6e6a121bc18fec8d72e85ba693045d05fcd666bcfd07ee0b31c57fbde842fc1b55f777731ce38dd8e435fc84c47a4607bf63f2e9879f4efcb5a7cca588cac18681fe75f241a42b041b9e4623f442ebd254236bef266e0e6f702884a98cae9cda193ff8ff733fa850523417f7eb8f598142d0358337133d9d564af9befa0b0a7fb3a57e38e5d242f88a515311ecd0e3095cda23786a71fcb0d5e8b8a9bfe5a8cb44de25a979242b0dec4bca73a6c74d39692bf0bc6af5586172fca069009bf810773873d4fdb76829283d9fda7086dc1e00f668846053f539c5b3c3945a034d8889fcdb9ac4c7061554158c572ba93feacd1b32fd852741acbaa19b0fd0135e76e5b55f892fdd0184b604f6666459b38687d9a5df2c840e2ea58036d4dc71608a1f5bc69a19aa41bbe8c343e1f752b4403c90c789f0d9dfc6d8b614e5c0b7d65cd4a3ecfbaff640d1b0fa87ed330e2fdc24794d598fdbff481719a2ea878a310c7df328bc986999ece9cb1e7cf1568367538cd3be1104d4a0e0d3cb796d8895f5aede6b095dbd0b4b8e15038d11133b951d2e4c7a84a4820b1ec7a12168d7c2441f0cd01b971263b2e4aadefa51a401b94041d30cf9a3e50ed918b55766fb2ccea30719cbfb9cb303d17ff19045f3475edddfea0f0ed2628d043be2e4cfa8d524ab5720fbe1fab0625530e3d4b80f40f546a21f3b70cd562edf0a9ca58075bed999d913693bccb07f87ac9588e2d98740315946893acd4808a34ba8b93062e3f9363bafb1cb5405b8a9b622555f6aba5e52a27e58b89b0b998f3763db0043a858a32ce99561d16d3a97bc5bb7cdb14bce65c9ee7d38679c53a15b74d59ec66bb0ce606098108bcf3b1f2f74c72c20b51e384171f8f0f7f4066ce4b79a1833af795f1da006abd6aee70404a20f117f06fe5d161299235eed824592d744b2a5270a1265d866f5ea7ec94cb0ff073ed786f060b1e23e0269b63cdff7647a7e3ca75b4e55138172ba35da8ef50ab459195ed387897c5aecf52c3a1d150accb68ac9946ead5691d51c7d1d3fd1c9ced8e75f35171ea9665adcb6a92d1fb602b599da3eb9ba0f58effdd17d2e8dbc5b217eb2101620e88d6d64aef6bd62743f6852db6f1ae0865a2d6ebe53602ac800a93d63f9b62d2f0ccddca707f20ba7d00d6869febad4daf45a0ceab6353cd6bd9741f988a37f1a6f340d2974befa1f863cdc4cdcf871b510f09e4d59088a7123acfef2bcead929755df4aa1262e005bb438e530716269024c0e8531590d66215dc72a0cfbf5ea53940a27123a2f2cb3a0789b1e67085e70e8f87e1762a0fb6c45d3fad900ae0eb8709dc2f9a483fd0e5b4767b5a79d312b8d04c1dd88583dfda79833ca6aaa3a2877d6d2cb37f14b9f3b2a1b21e98addae5be59615cc5e74f7dcfef6e428c126efc002154f79669376056f428121d28cacf0eaa75dfb312a8e61602bd13174aade3a025ef57ff7dc9db978cafe20f118a0c4591066bd4ce1feb67742a480a5c5617e20964ff740f18a1a8d75d5ea37b2f3c8dcf41131096eba5d5017d5202639d6d2f0bd79c12e1f92018a5d114ee735f395d7a743365bf522a98c49e02ec421b1678fd9ffecf89b2a3fbe927dc683900502f8fb1cf63d0ded46635d721f8b2afcd96408b9189be5dfad5126e334bd091adbc7157d70aefd5e89f1554467f0bdef7b20ab0f2fc5d1b2f121b742834ad40f9a00b3576c1d5639fd63e78a24a9070b3060dc8fb5ad6417efc16b5fc02045f309adb5cb943ba02b742f9978da9c8078f7b29865bafafc9093bfa5d4846c53cb5f57d2cb44a38dca4bdc3bb6dafcbf9a6341df8bb7e8028e78b5adde2be4a6d0e735aeaa0a78a2c5fe3ec2beedf5c7e8ba093290071fc0ff5db74b80db15165c7f61d14a01e704332f354b4992524c51eab3b5a03382a1b27951be3b0e6be4a0c343992114de036a3945297097fde023d7a402c2979afb8a1ef6d212a691124709fd6a88355fc4b5e93cf808dc87f7ee5f789034de9491329c876eeafe7bfe6e4df386674b7fe75e2b73db88700e0b5355ff545a1f2fae9f0381483176987ddf0daf25a56a93262cff6e8cd2cf47e85446cad9c613b2d9866327990e6f12e2612b4398b3c865c0a6ebf62f8370ca141d791f787f586b3a19f2d3377c90118e032cd60fc023e1d0003b40ede164815089c821b23a08aedf5bc957c1bce776fcf15d5395f6ba38aef0d470cdfdacb1808935af55c1f32ec4339698bfdeea62cef2e58678d568efba6abd0d1b909fdcc758dbd6f831525825eafb47425300b4e7b8d0bf3ab07ea8b19efbf2f5ea2a40f3b9ab5a761b871508f843f6bd71f482c7eb477260784c82aac96f0209b8288e16c0eec74a6b686eb205c667c2d596b6bb1ee519ac8e7d52f388e4e9dc7239188289fc4d67b43d0a7f9413d2505cf049e73355433d07bc0ab620d95876c4e136c6b0878bc26027e6c7d9f9c2fca17f62f728110b11ecac480f06504726e7e4dd84de4ee31888763af8c8b7135b9c38fda825e8fe4049314ab451b979c6f50eac8740217e4dfcedbfa5e5be3604469554cb922bff3308edb2591a4e2850211d8060c150c4730c175f1db996cd8aa3f178f2c7520c1409eabd7d297ef31249ae6a0cdb28aec7dd7bd2da59eab010603d8245dc2c69942b94f0c67deb5cb00a6000d6076f102b358f63ad4b27477561142a5a1acdcfcc900e7e8bb4dc0b200402e3df192eec72fefb37650505e17d93b6a122db82b3b480b93dd95bbb89e1ba037fc3e59756b8cb28186571480216defb264ffad3bbd3c90b8ceed15db915ba5b33f35f32d2bba801d414d7d2dc2d49f8b27521da5c412c6904e5c2ddd6a5b208ecfa661b6f34e7d0b57dbb05369ce8dba307ce82a38aa4ddf2f87890aaedf4ae873f60c239b2ec279d621158aba0b81d0eb2a799df31e729405854298802f5788e9c8881aef5834e46a20cede05bc593ff60bb39a06cc71edf2d2065699355aa1e195fd98576cca30f560e2eef5f4a2e7463d886f954b08696a1703b285443321e51c8f5f10076761aa6f0c16e9877a1b7f3dba4dafb97bdff3f36a288bc8e8c95fec87f26acd06c7bd254b173957e5a07348a39a4346f6ee7716ab34c69e3b5efec519b6821b33c1cb02e6a608c26b2829371ad2f85cd6cc5226f8d6aa20b2c5d677df4d55c781af156737950562bb87a9244f665e35e6d36c814ef46075b42e0dd6536bfedef6781bfa94d6b783b099d621f91cfb9878c6fffa6c27456304dd263fc7fbb78b150124fd138c43e92c5e23484bde15a769cf8e19eb8480158ee345fb306ed266009ecedc9356a82dbd01e5ee8f847579ff371d9dcf522385a586fa514eca29274c6fb5bbd04e15861e511bb72a99fb34d87cc6c180bb364be43be0aaa0cd77f20f47ed4aeb220facf95d16ff8a939d5f8eb70a70aa7a8939a7359f0108d8f1a69b1e848c36166e9f8960cefbc0bba014b368975368486fd9c3beaa571c5376a2004589dd0aa6b126cee73d715cb2d0f7d048352cdcb84457e0112adb3460a57f46916aed9f077ab5d36ec15324d09c6c98ebefcc4eabc3f521d771767a8fe79cd5652f707eabb7999ae6fb5fa05e246d45a48f797cfa60ddf4a09cb930fa74f0d85be85fc6cc9df84d2c93927f60526b2af0a1194b716dddcf51ff3b8db907ce51f1dad9ebe8deb7597f7ca6cc5315f722e441f1c109d7f8e50f7e47f2cc77d57ab6c1bc26b9f5518a32f62ed7796a07ec4856bc10502d10c26af427e3b31bf7307d7c1152a90492e5482bb1f21ea435b9b3d1ac749f2b22b9087109962aa213d6ac1f86d93dad13956e10b263f213a179816a6477b0965d95b595c5e3e0e9a9474fc66ae40144b1c20026e38f32d6991653f6cd95c603edd71f70fed3c16f5ea9de1fe9c4d30b3d94048e0f5451e4988707cc654d61ebc37185cdc58e375f321190efe027b9fa2514d275e2a64eb31ba22dc6225242ad315988eaa64bda9c89163de7549cf2f07747c97638c599759eda54cf5beea724220b4900df93f749d47023013a4b670f045de243ee3a8f2c6b850fbe66102618ccbe81f27123eba20c4ce2ab32628cbdb143cc34a911c325f483d81af5e65d402ab8c4dbca89b626608c2199a258ed8785587e351c6ca4f96072e591e2e10c893179c157520800816d06919d11338ae96efc73e7c1ab9919090eda2a906ff7fe07d867da16cff36bc58d8a8d625e83014f075bc9ace2ee060a5b9682d8d82daebaafebe4e0a2ebb577f2cdb14e11dcc0d8e7d557da79960cca78a4b86de20fc1681e8957984a896dfb1e0d9a3e2f8621b16956e27349a6ec0b32268d811bfeb6f084ba44ed197f329772dc481f80a5a4a6e478d199b0898c40419119045d0dcae0aefa5e69a3c75b38461ce6168dcda6fcff2666021f2a1d0f8112da20863ef6f364a468a79c5d2e661ea657f4f59bc1f70d7a6033a81a501838a7617b7b26dfa2a85bcc4728b99537fd426b4f60ca1aed2dd6bc9df949148fdb72201c993a7bd3efb97c86bfadd89c3e2e317571c868076d3a846767157ef8be23c1cc0fc0a695c74b235c7ea2d8fc9ff29a3ea2bb345c5d3c293307f32654774eea662b4d3cab41f7b6fb4e10aeb0b14b772177d3c78f3f5af0a9fdbc721f620107e498a7194113fc00c256551c9bfc1b904cdda0969857c3122c4f012a24d432ef1d199907cc1c7843e7cc27615ca588c1b673aa891d088ed9d78ff3ca1475ddc3e3d86f76c14fa7b2825d02b5f2f5b130fbde673f14185c7cee8c005b5610c85cf60878ceb4fab0440677ff3a17b7ea209a514481453598afb4056f49980250d183e1eafed9c045b2b563c25f8e847d672bccc386d939501fd1c054acf0e6e0b3041547266ad51b2f71c39b712270f123c0e3211780cc774272b0c13f80d3920540cd3afff967fbc8e1eaac83e5ef1b086c97af143196032fb87d04f2444f2d47ac541dbe1264c94264ceb01696c02de4e405581175f9577e604e67752288bbc8aa1fc046bef2b64d21c4989f779f47e9b7689cd8bd208503c1cdd9c3e5a643c96281a43c996027e1e2a0ab6109de3f2e08c04449abe20dbf6c546aeb56fdf267d18ab7c06369d691fa642e1f96c6722a07eb81b178d61e433ef3d09d30e9e7b6b2e4bb2a811ce6c3633e9c13e09e6f30219c38c7c5fe79d752883fa0fd08e3caeb23e5303f6d8945cea30dfbaac4b8f366bba55dbcae9418d2f251dd3f867660bd0c3b0e8d6ffeafc2d79b63155429adea5dfe6988f5569a4c7a8b95202862b99e64c66c93f6d81a23e789d2ff813f4cb51dd4878a380c6098f83a98d0f456f0828dbb255fd022b1ce9c8be6625bad5bc03f3e4a624358dc896eecd7e93e26794d6d1cde63e85c61161ea44a5a337bbb67b0c2dbe636e0ad7eab9ca92ec16af03eebb725f2b2cf6ecf01e63fa4c24b1b3f54e36b84783b41c3d48a97f5452424049750e7e6b5bc48bae25c93373cb6046ecef7b69dca75d9110451fad6fab1b5cb336eacb389e38bbaa327f4c2365f38c39ad4facf6846e8fcbfe8252160ba5dca857212fe4ea3d324160a70f8a6b63bd34b73e6b06da6d126f7eeb73f8f5513d8d1835b9781c48b5cbc1554bbb5a1df1ea01385e0308d592153298272f057b13602b2aab9da311dc0e5e66e511f6bdadd3d7b6b71f3fb2e9c9e1ac5ba51b26e57d2aa373b0e2d8660bce8e1c0c860f3dbcdbcc7b7bd3be6abf3b7a9474a33a953edc532abf5ca91f0de6f393436aff6819a51ff683a6efe6e2d877d5d81ab9b016ba3118549586b9866d1c92c3a5cc1c95a251962f31703949701ea28269ca5668e1cd9d03e55e933a23ebfee82aa301d83c4a274c2bba25b71ba865fcaae9528a4220c13f3a1ad0d07894feb2574d4fe6e66ca8acf144d5caa3a6ee4f370be7146ab9aab9550d8a7fec205a30c582d40cb9ed3264eaaf2c6046208575ff0235b5fcb0633b6f1c9043ab75e206ebf38bf103ce7f700e60421b1bf0cb8a4774f9f0700bc537f470714fcf29b6ef6c6a170d9bdb36e699a2d89fc7ddd671c8344f566cf07a841bb207e565c066905266abfb88910a6f899ace538e40fa773030d9290c67048f5b4060b7d1473cf370773c9fbb591f151994dea67b63bebdeec742d982d609f1f3d3b7b80d18c36f19ed32f52d7b3c0f8086f380d68c5b286c24b86f84fc3ead2ce42ce931beee626a406fb5d21eba380c78592accb148dc51de431a3fbab758124ab3275fc5c131e478a189531ddf03b03f6287f94107259671dbfd03c6fa7ad254050f953a449c28d1fdc3714aeb9122fec659053e6b7b06f7f91bef2b4a9b895f420163509cef606ecb6542090c2c155321ce1a34c75431d12e2eae2212ffa8d6e637dd37ce8071065fe8eb672de1bcc00a3454a33bc41a0167bd646b86d54884331bb71c1ce8f7638d48108a77ceb1345c2a5a0a7603a6184378990eaec8339a549ecbb1cbe1e9498ee71f2b3fbba41340f7026f96d7c8ca482ef3969f15ad4fe9f3169444a097beda4256c14da5d1c10d138b8aec8c1cb15aa1157ad1411955d9285fcc74123998da72183c9d878bc870368343e9b94f92e9eba16d73d453abf0e58013aac9593552cff42ca3eb3c05cf7d5d8bde68af7b5ac1ac5c517a7e6a4c2ef58ccafd613403b913bff23bdfdc01913653c7fc15c33212d9d551cfb10b38188c19fa2b1403946e9f4ec7be1c2bf460d2838476917a45ef45b8a104056a044c3f774589a33726e580d0803cfdec89e04ed8ced546758e3178a0f9f8bb6fa337c0ad6ef42e1f84e6d6e9d1376ee2c7986961b1a1fd6baba57b2b2d1479dc249f0f0b86041379a22cfd5ba6aa024c8d63301fd9d5db61457291c4794c778fb632ae41d6db36f26299039dc7506a7a00fec44e69b5567021dda983e42a3bbc052c48010446b8704c57088e63b1c10f041b6ff7bcf5a68a62f1e9a55d12b405ede2810da7ef84f83f14dcd7c2ae37308c1b9da7fe069bc677fced0b6baeda49b1f29b911c8696c4e01d96db43e92fa2e8a9099c0b98c953b729a2d2bb6d367334a4908b2538d0bcd0d71d16154847caa7fc0c72e4838faaaffbeb72c42787746538fde3b9100464d53fa942622b76395641b278462bf904822909571e8ed2230b2c29818822ea604293721cc9241205f80cc96b6cd1000ca9698295504a1f9b799bc2dda7c88c6f227683c0b8f29ab9bc03823a077f025339be85df94df413b39b39a432fc6e78916ec03e196bc9490d42b792d1d46b8221d02ac775f678c3126ee5fb21f61a878e4e23e39c6a11304ba159873a60ecdc58c5cbfbd29e87f9bf5af8bfce6e4f234e14fd738a400c28b53dcc312cff9da87d951d5868b6f034577e3f06d059842bc39a5c7f8e6b9574af675893ae549a34176db90ddfa9ca8eaf15641c58ec1299c4a7c56b7b05c0a227bba9db2d2fb8715a66da6b35d0497d72734197f1400f11d8bc680655e82114a296641a8be86e38ac7cf2ab638ef4ff462d91370e10c5f0c830b0fd1e66c178e7ca614992383d808f4f1455ea157bbc579d1b2b2624bc62754e48df5a560884e2b53251c6ef76d0a3e723fe2f57232be6004d8ee6745d8cc523579e335511a8b8cfa0372045dd155774039c16a307a604c552c69925735bb7b9ca1757e137f6e8a11939c3819a5417ad2f7db0d8291320bfd3c78c0294fa0a7f760338a9836b58dbc92685b64b8f871e82b93042a4891440ff9bc947619a15afe91335688bf97632e5ef7d5e034fcea5b20eee55b7e7ad2a6762f665c8db6878477150709f3fd90114b8269ece597320390b69ddfea0fa5f3b7234c64f9fa86eb0c84be01c9024a1642908347934a3edc9f6cf987656c043c02a3c2cf6ff81bc9183c9bc95f7e0248baf18e1945378351763a019dae63b41615a910f8c9883629f4d8f75e2b2b92a70476eda0c61ed9ee47d060539f81ace0bdb369697c19f3a1a12e409c4d87c28f0733b445f7524fbfc4e26c33cb01b954d1b35e544c54806d055340cecbdfd590c0cfac05a40f2892d0cf2a62e1b4c26c42552361c3aa4494937b51627c950d599005ce505feb4728e80d8877892ecc30db1868f1b415ba1a3403f21cf0b470c64f7b942e4b82bb99065fe870688b25b7efb7051a73536e120b247550c81890340876dea1c09ec35806e9ff1860cf694ea0a376aa69bc9f05aac8d3b617057fd2a61eb09489ecaa629a937e31f3985fd473ef71e5fa5092d246a914a7fb8ce3cf7f360b54c564e20a739a65ae677e239d19464b60bddf4ae307087846f954dd28c2d165ca9ea46cb0e3330f2d0906c3d8060e43cffb9083e9a770b9871cd542016f1e239fe10472902befd4f05ad158126fba8280f179588bfea0447e60e552f6241820758368780bbf77a52de82a208fa9cda3e89fcdeffe4d5b58ae11e7dc1ef1e5633ac4c23ad028fe70e98b72b3c0bad693f34566651769ab1db4c7f841e9874ef1b52b86f459ed5a87ece2995a20222911c3121643904ba33885c8fce9f12ade4c3af05c0dd69216a8b28fdc3225518cfc3ded8cf365eff79e8bbddd7587d2b6935a8400ac9001f5c694916cdd522331a94c34f1f76f4315dcf6709c96df37dd932b0a0784bf4ee02bc24f49a263d56efef3419ef6588a8329c1bcc44349ec174391215addd9771bf475e729ba5b3cc9b8be68f2e23b218c037fd42a81e4fd29ece763a809af49ec6c6fc1c01e6a6783fc41e9ef2e5253f6ced59cf632395abe5dcf2daf257155b7a1e6f751ba89ece908edcea2bee4f113e097ff97ec20a51706864a491960c66d96eb1d018c517be45be641f43f3865974dd4ed2acf14d88448f8db125413c7fae7d83888d3350cc4053f98d777be142773df7f3d1007ee467547191539dbf9e3136a25473a84c71703f29143a74a4227f85726678d854d43d04e01991b38972c6301f74c611bfd67ced2b1a95f846ef1f4e753e9a63192bd3ae9c178fa62fffb70d999ef198feefbb7a7e31f192113c9c3ac50195a60f03900234c7face6dba069b499364d79337d54768a216a8b828a3f5e81b4a9b6b0db72f03a1a118116174b0063936d2e64ac80b6c388fb75bcdd0ede92b401c7afa24b0c57b41446de20e8548869400e51c8ffc3d8cafb51e1b56e426172028df58a20195cca0c29c9d1b57c9061a9f1e879562acc0ab8ea546059bf4bd49f1057f8e76d33b81a1231ab5fb8ddeb7825134ec4bf1d48d0c55179f6060cc5f8fabec7ff9d33df42cd4c40d88f39345968fa094e1f62e261e13eaa6b0f3ba8ff70baf89f3cbecc6b895f145a50bfed8db8615846711e0be83aaf21613297acb12f49d67b6aca5f23ca2378de6be857caaaa2261cafae58729c8a3c27107580ea7d0a825639f75a4d4f1046204f44c1645bdaa3f9e09e3948d0f96dfc28a971ab053ef53cf0e010b59b8f57922d52e14aeec527bdf1ccb758f5ee0b4a371ea0c5ed8e6836d28f5effcff8cedd23ed02454f999077a581cb34acaefd4d394b257ec48432669b8734fd9c37f2f928044fac9445d0d90fcff5191f300d78d5ccda493616e71444e51473a9c1e5a20a45630b6c5b731c602c4143196c481841af9ca09e0cf611c3e41eb8085b698ae6710f1d3f9cd26e562592ce56ea6db4e60d85f49b3dc1cb7ba81bd0049a90a0c050cf2ba74903017d4d7ebdd6cb9c4e58dd66c3c762f8097d8ab8ebd8293140db12a2c46b281ad5163596fb1b9d57ef05647cfe8276299bb38131140a7fb4ec57a8f944d597385b641d12441c644fb768f26071f3795d66fecb9002cf77895ff3655a3d8dd2d99efdc6e7f2ac7ed6c47f8cae6780820552b7756d8f8e79914805891ede037e3d3889a587ac755c0fca003e7c878dfe3648f0e735cb1420e5fe7143d675647d9f1147820892c7f8d38ad901df306245741045f583a325deab4ad2c7f61cd6ce747fe09d2de39a8188e0da1c336ce11c855f2209eaa957037953828462405a04cf31b22e78a37227ab4552ef6d06a8d58effa3685f92ff255d1edab16d454ee359f99e09ebfad640a77b9f1c919ca7e80e2b3a4ad16151197481683f50bf9ab33c42c4edb0f0b986d2ac4cf2ec37b74c53f321a67693ce7bc88ee85cb0f9bf5e12c7790ca04e37cd8242e33b3b1db2f6c42176865a268487afb2752d995cb7bbae31a37cdee84f05542691c71fb61ca4df4aedef23774ea1df49890230459728fcbdaf0c8e558936958a82ed86c6c5ead27e297ad20cb571ce5b6f9cca835ad6ed5211a4da85111ea938d480c6370396bbc92f5e0d36fa70ef96660d60cef13e39dbfe1a357e480028945b22833dfc814e727476e738e60d31a3bd5651eb328e9d20d3c7f88e52932e877139458dbd12586b52c44fc3ddebefd7a2a6519721a5a4f56bace12e0c1d0ac57d43c0e426c5fcb0c2e49e81baba5545033eb8e267b1f5103a7ca8e683f20e213160eccd99b61f0faebaa1546119c62346d1e2ecf31c5e01a83c295a1af57da1315c4f1b782316537e820d4c6584dc14008f321bd0a4ee21979a5db2a8c7a03d146ef8b6588e3d80496060b1f1ea5d60d9a07e68ec10b642f860e9f51472e4818f5f47fa314a5f6bc41979ffc3769c2e588bf318b5234659b97758fa878e4df95c2e0750531437097cff490bec47c22c6edf0a238d76d8db690a646e64c9570761eaf2d5bf7db879b20d849aa7fbfb7e59fef54e3f515e54b7c6395c598ead7d475952cca136be4f3045fdc56608c44f00b2e5b9cbc65892a11f19bb7ed9f01ec8a06cddaa4c029333bd9aca6f5dc5c3ca65bf1dd4444f8e0b445af1496e37cfe1eed94667fb64a88ffec19ac55b1bd1527ee5ad01f96fc44afcdef0248d0e22b573d11bc821c7641ef79ddc731d4f3e4a77c9296fb99505fa72f96f605321085cbc7cf9e27caf278df44803858a541933004ccb5ed69d2a6df1c5dbf618765fbbea64e9ba3a829d84ef5fb28938450dbee30f94739f43c410e2f4af9ef380c8d1b3b4742793b475b748ead7863790d7942cb3f0a5be9830238fd7feb6f95761e4ff652c10072b7cc7db5814df6471e718a75e40632105d61a50d22bb3e990ed38a11c18f26579e1af4678093ec013a87ba9fd6b926a18931a0d5f219e4cc76361aee62e51b308421bf2661645e547685702ca674f1ffe1b0ace801d31251ffea99278686366186167256ae370ab9331a0d2d129ea4f7f519c232cb4b99305236e1a8ed431be55bfd17f8667d079581e3d3224f779fad2423a5dcd933e7558feaf73f74d726a5690097f960026e892627b5dfd08f92fe9cf120ef4b73ce89dd3b36ca9cb2a96e89d9568120659eab56014383a2008a5c3beb0fe0fb27fab6c2411b7c2c172ca239d1b040028d190b95bd79fe41314b845b3eabe51a3fe4e9cef0f1932f7fe3ef0e68d87b7edf3483a2c3b78d1d72389cc9400ed570ba0adfe0d6f4b0cd9e5f860870e431833951123d76e7dd90f2286caaf94d3d95b60dffde925203dbeb72c66c2f9ed633f639fe75ded22a1036fee3cc6345693f189be5c11ebbf57bbfc8a9c47b0dd12e47e9b5c2a2318b46186e2df54231bf14cd357f7bfbdb8abeb8db4386e6cbfce6db18b54967092f0421f6de5658ee95a0402613062b61a15d3c0060f9a6054f52d682dc420e7abf42c779821a9118b0c35f1383ba2707a72c8f9e514685dd9407d8dff91c5478e96ca8f8057cee90d9c9d1640b7eccb7c6118c3fb45aac31281ee951b8da437ed0193c2b8b572c793cbadf61c1e5574948a2ae6b2bce2dc2275768e32bd8f4e760947ab86f6fc4da2badc4332d0fd8ac78ae6dee3358162c2aec81a452cb6c04f4ef89254956683f6cc179d9628f5614e93c1abb569493c2dc4919a153bdc16a9ce200b419ba4db1dd531544785cabedf62076b590f4baa861aaa7ada84f9a2433299dc96a2498cbe96014c7e135df5d09b2159027d0e2b7f86f88e580f8e471874f7d9b062961b0ee7d6e4b1db97a472d7c6bd12dc0571c4d13f9c504280f19b902d8a03114013d399f49929d4269c3f6eccd5c69649e437611fb5edd73f7fb938ef79b3b47accaa204cd8f27700b03699dd180feec79ec4db91196adeb0e872abb52a5bb644c1826adf9f6f8d4b788bbb9f86086553cf8665459323a546c3848911b21f9d6b4c69b280c86ce379b81d64971fdc674fd8a9e06f1dc82710a789e86dd2c0585fb257559e24f2c52afe788e43b6a3ff7838b24c313243e6dc83343728daceae29918f31252b28b6ddd02fb44f6ddc01a4cb0099320f264b72caa8f1a1276b75dd7b19808513a29235a63d0e381f369710c60d75c02f9bc10e3f8b135581af74b5dec62eb5d985fd08b945de054950401619b6a158466ba0ed9d96e2ae9f8dd2b801da46503371a903e7f2e35efd27134ec90ba66c6903c9b52d0b02d19a090b57b550bb69082cea153af295b253343de444d57ac3c3cf2a5531927426f781ba56937e5b05df07f0ffaf4323e48ef877cb76c531f6707e7fd4b162526fc907915e659853523d164bb46fce6a80ce700e94772256869938e08ea685df7add0dda126e0249e4d1b436a4ecf0e98a8777168503ec836255603a6b0f657d06daad68eab98bdcfca5710f98c303396a6fce18fd119295a152f510044b96d0b4364d8abeec8eafd25cce1a134e04a54f608b9469af592663f4e9e046cd52c2ab3920c2a8e85d2191ed141d51429920f12e3657313b15dd481f4c2aff506523306c66ec379cd353a036929c596ac7d5386d20cc99b18e185459602753c33cb7824aeb2d93c19d1283f4cffcf21234223aa59da0ff71fd764a30ca11b237d15e94a082fb0a947e224d9768653b79fddcf8cad52c7324caabc84df68819e5d8bbf1cfaaf3f6c0aba11e1db37a99fb406d9c68f528ad40164ee1bd3eb5ea9f4b942231b0afea80e46b141391c7fbfcfa7489baf13d443fdfe927f007e0c313f049a427ad2df662e53f1b8aa26937f0a2b698b3aac6c555acbd64fe0c71440ace91cfd99a1f04887f8652b6f7002a2017fab10d9129d3a601ec783c3e6743540638fc8fad5070130848600261c3ea97bcdf630dac8eb1a0ee8d75b12377adf7ada4cd1588b2169b1c3a5a4420097ea9bf72f0771de821cf8c4590b7590f75b7273fe9bdae791a3f2d0ada45182f90615feddd17e7d26d3829e5211e7c9c806db219fc79aa34a7f7a153a66a22572b08c758c190a2c30095d7f77e487bfc34969e9fa0f713424333280a8cb955c66d52961ce009223a5d41d07ffab713169433a33cd06208ec93be23a764d892e12ab1c471a2e6fdc047377c1250505f2c42c75ab8cbef6fb9ebd273e9046143b608c9f40678d21c7526d1262a3cfa6e3d8ac7895f2aa39e8dfb7623e66347d50854c8f8472864418ceea84ffc886632d9f3872d79b3d1c3c40abf0e98ef00509ed8d9e8df6feb9ad4522bf8d03c90b37d8faa863e7ff561da5c71e1cac804f5c553417bcb1ed3b3e6fa324ea5a3ff765e45fab34222981f538f00f5cab468837ec9c7138bb25e5d427e9be59bb8e259bf2da9f61be0ee315669395eb1e78d7afc642b5bfd7ddf2ae683c2a3efb276f66bcfc71e97dc38b41fd1dcd6f5c09f86ab52330690dbd15a108d0f043c12f227db70103972bb15d88c917a3ec51f50bc61fcbb89fe69dac180a027f811e3807484fbaee2c77370953553b86036b653e339349d08e2b9d6829c99599896758b51cadd298e28bef62f141c062b0b39535a0cb48e65386ec8ee73437315d8ea24c448e2c30d53e11164d6c840263b6d6e69546eec400f5e64aed3d4b23a16ef00c744f740481764511cb386e8d93e66946624dc01c9c00adde07bcdd362c20b72307753240dee36c44af81995dfef6b3bdf21b68cd661df548491cc9309b8f97d36e20f254fee54fae316726f48a411ba5b18b1fbf58bcd9fed499daded65a4ff13678fafa4c3c71e708e0b1d68a7d1a9c84d11b8dae877769afade3e38d1aebd7cc2221a76a88fc04d35255a530487dcb5e15ebc22d5e478c5fcc33e428304940ec1135e22a2c658ae6c42c7a8f827ad4b1684dcaf65da617d5b3992c381739e36a8212279aaf5ae8a0d85b9066435cdda2dfbf5cfc106244ac5409b1ec44ec4834737c368027455ae5a433f1cf6b230458346325b62ace30fc4658ac1b2fcc23771b8058af3c9fab827a073e338906d95ec191e7ce0217b1c211fceda1e32bc33e780e35a0e12244bb352797a6c4d95e220b844e59d916dc550683de35bb59b5d1178c15aa16cb88750f65cf417f10838201402f4309ce9bdcb0925b83d9597e692539298181432d123dd3e33216f6cbeb3b23aa2aa352007b0949b6690e91712389dc3fb2ac7040a165c1cfb5bda40ab9e62a5be24c9d63e820351e8301d694efc19cf2e76c0e378d4b19200b4c9c2f9569a0fec4bb3e6da4b5788d8161efa1d8e074e7d91fdd264307d395b3555c00a1c64688be6c2f7ab165029b915199a54db91086d6fe708e7eed80701eda2b2b1dc9023ef9e5c3acb5e6f4549c69ac75e1fa6316aa846c3e75637def33d4b9073b439ecf003f5900134a15ff37f3cba14b2404479fd3b595c27fac90d7d666c991b64c0f50daf6076567ffbdeee50710dd78f06fdc6480bf142fed8ee75e60bc57938211d1aa1f1cf8c980af7788c39e975d30e97ae744c4547d8f1dc1b335894e8dbdeccf1d3ea99782674f68cf9e8bc206d89a640459aa16667bc140eee4f9c0395a60252b29099826898e1406fdc6327323f96895d3d0c2bf4e2fcda47f8517af0ab98efdae40cf18bee26be80c9f8a70872996653016530f044d059f9072a098128563e184be6aaea027b78e81b75447926ce8a1a4f7a70f8674173d9f5f51114145dccd8f829d08f625f5b96b3083f3000438a59ae343af6ca427c48959c08cbcabcc63afe75609ae18b96a55ada58a9602347f791532c846357fa63750fbecae4e427334d78ff7dd270bb3c2f9f5ebb9e2f25c0e3a00fc6abcb45a2e3ed28f66e700bb9891486391ca0c611517586d25f57696f0e130110cf1adb4fe1793fcd9d9821c6695e9372db7583b486d5a6beba8275925af2c201486ae49f8dd49132951013e30c39ed1df07217ccecd43581e01974ad2c03fb6378de6f763dcef7af4da9e5224ded0ed7d61425b004a16272bbd3fab4fa4c4c77f64792b9c929bdae4b206e613462af4f26db679edc59576415132967589c6e642cda606aceaac29a2744b86ceab0f188cdcb032489589743112deac1cdeba7be0759fb031be123f65f83a0ac0605240e7c6157d689c12d6edcb55c05315dcb558a58a9582b2de50447c539d49ef7dc8be2d9afa105fc602b89c36207c4fa98660425892ffffec7ba5be68f99597c5720d8a35a8171e1c3f550b4416c872a9e46b1b88385ea16c037be7419bc97bb55c79f4f90dc94e877215926a1f802770e27f75e116d35130297cd62562f87bde66bf883d7032995ded31304395fb1fc7232032da400cbbcea4d840aadaed1c56f422da175704d888a026a903c1b19874cfdfd39e461eade40d52b639e14c2bac88dc62fe1d2b742e51525421de458bc7cb180a015097de13e066bee53bdb0f6dcf40af0f1447d20e00711f9bb5546e5f0ec82050508c1693015a204e2cbe42df1c9120bed10b7a666615af0e12ae11d2290e1c97c32f0568a2286d1e91ee0d93e0fed6d13514c70f4c408aecbdea504ee4ca9954d9c7e57fb78925087f67c0a65d9d1b8e3b6c6f3d48821a2adbdce5d8568272df568f1f78e3e2a57f27330acb45e8f312decb162071e9c35ac9f998651e9d9a84d8b8586a280baf05303a5c4f89aed17569ac313a1236ea44cc80d833b31efb95f6b496bf161c8c9a863ac48a78b1de5821402798cc122512b1f451741d70d794c3dd7b09d54013db07a7f93252371e6a18a703c21daf859ee801f7b1b63a809531772ddba6f715ccacaf581900d7ffe717f57452e0dd9f334b8dffe56be7446c87b423f2912997bad106ec8f3010a8f61360b9d4d64624af0d935783ff6ad3c4fd74188f2fb818f89d321b56325e7235ad7ee2be548c08736dd857a2354a17937d34f8fcb934dbb0fcf4cf0ef13304602f5acec71a8201f994e6499dbbe2df70dcccbe1352c7a4ef74e18beafebe4899b74f6948968fbef39519146c96abacabd3e1332cb1196136aaf0b1245f32f8988c4078118dce3ff836b0f16fccbadb0d1ba51f215ee9a449ad0f820fe0a5747cbbadd75a1a50a39b825b400a82b5e05e2e1a5e7d777f32be859c1e13221628144fd13dcdc80530b9ab9c221665fd31ce5f6ee1fc4c78e1bc7df8d8118c924e1724276471bcb26bf2302b17bc8cf0386be1ec39fb32fc730ccfeb3f6ef1628bbcdeb8f3b0e45fe54f118e275af89b83c765fec7da5cd9fc1cf8805d87f263a0c1c36929e42ac160cc6f86c2a58b1cefd95d4a8ee9f72468322074d847027e3ee0812839e9041f3e55a934908db8162355ab8949a1be93ca686a39eb421dea5b19fd227b5e64d2137d4d39a11f709252a99d52785d812fc5caf7ff7feefd3169449b0910424c708a665d5311104933b1153e6c3e41cb87088c0b2c0f68a5b438da0f5d61575aa248d6a1e674a394512128a23709bf69c02478a5c035b0426231f5de465c259cfb20d3e3a393fce9a4e031d6dea6d4b306779758a0aaab18e92a7955d32ef4bc4782938a37da76a851f4f4c4e3a99278b57b125cd73d16fa8b1eeb7555692ef980468cb539a23feb2ca9b6d2339d6df0af3b5ded8c07fe95479c513e2a8e2b0bd27e729ecb596e8d28d76a9dba64d8a4a2d6e0ff3024f1ad346ada1da59f700d4f8d7d6909a9eec27b5a47a46879f62f66d08712ab0766d0dbd2fe0123d0d73c10677acc51b3a434910a2fa9dba9b9ff30c4127b2a58ef3b059dede135ce89ce4b5e94457213447d3aea6abb616d84f38168479a1be4a7280bbd71f7cdaa751926f14dccb2cf47bda7ddbd8fc27fdf2649b3c9f5f5029d8039d6c032bb69d41488ef13e2e9dfbc50d689ef0356b810aaf09de4c3ca2daadbacd2a4a71cd96386615f37217ca231262e8a260899e325c5fc4df4c9cf584efdf7dc084cd185488fc23c700b5a9b10e3da99585c06d26c7368c9e708d3b0d7e4f50810289b4134a940e44657b9d335366932cfaee55c159235491c2b0ecfc6904f56cca8e8ff9d85e7773f2998e4b89e4169089713b254dbb949a2db605cafcec488808c8dc8678d19e595d8ce44ddbbb4f1a9e2a3a29e5bf9c5ff6df0ae11a8bf7c6049294473b001fd64f4f194234e98fdb8fc3336c61d52a728be88cd84e50c60dfabbd704b9bb9c26dd334432be36f7a3b5755944a100aae17ada4c8d594fa0b685af7f876bccc0c5442fba2629523cafbc730077c2fcf28ca168cec9c5075ab0d1f1c9cc2437a1eca0220cbca10370c835b8a92021ca2bc9f60b5fd4382031082828a452ee45c15ef3bf5822eb7d8463aa72c62726d9d924eb0ee05ce09fc474813cffc8baec4252f20288083c795a940d818a4dc367fe6bcb39b0e1991397c7bd849f7fa752688632700e3d9ae93f8f5032731b07a228d581b13af53b6f5b5ecfcda1e8f7d2b08a5c5782864ad64009c9742008724a2e55057b3992d20bf2f40eb81b2fecbe25a8ea8ade3205f5bc24bb63ddca64470b32e7e03c0137db93283e67ff7c1f2e4afe7e7f8cb0f569a04f802ace538bdac8b7a259268af332386fce73cb148bbb774dda61263a50e26318905a57bee28bb9526e568acf0d3d2efefec15440367945b28194f0d429ae3d68a4ef8e58c04a87552c30e2158dbdbf79eda72cf429637a80c0944eb828da3a9f870af12d985c2060372f79acab3f1a4e04a133036934282c700d528ef5fcfa56024dcba2942d734c5a622c190cc951b56060341eacc8b7b40e5b40a41f3138da2413a28ea832db2c1a683888acb3b473ef3225de9f3f882bb0c9e3d9dea3a1cf170fb160b37b413f119d268b9c3059a79c8dc18ed9a38311172f2d10c468b060f82be3c9aa75b916d0f6b0c410c62b61c2935ec23209627e51f3fc2a870b0a2851bb19a5722cd36aab1003feec1470e854f985b355fba2a8b40306f382ed006c7e9e3671f6d1010e9cba8200482e4fbcc874238b8b7473ad6f4f6a4ef9bd6695e24c55126e6220a7a539529e51532803be1fe811a9667438b20f434b5c4318da10a40663feea4fe41323aa33fcaae22cbc89035e5ea797c936d4373c95a9e486775a60657fac0716d868bb116fcf3036b46cce36e22ff3222dc409a5cc92ecc7901c2410245924bd2ddce28c16db2bff562254bdcb7a674051ebeaa2410b83ac8d3c1274f3121d544cfc739088e1f2d2fe05855544b44b809b97980ae1c37c4c586e50053f200074cf1ac61236f43cb7ab3a350d5c7add7f27eaf1866a187a0410f5e7d07a6f9051f51645f60304d25259be93f28700cf59a8c700f38a86815fdfea76918134fd9bd99bc7776b7987956460ccc4429f0300d527aa8c15782b833a97662edaa408a41a1c442607b5519531319de15e9b18391d6bdb7d208e0b787cbe310f31e9d8580d4455ff44e8899d67ea9de423e385388e07c5428902879c5bedf30f92270353ac458f65a46f3fce37dca06ff91e7636091b5281d594685d0ddb19916c16ad8fd6b4812d0175498c1131347438ff0848b23060cbc65de1bee7a395589449898bc2aa5f7bc00ee435ec82d4732c41d53a74300e4d546f8fb734d16b2c41b0b5f600585b0cda54951028bf2910a11057078f09fe1e1a76aaa74398a438f01f3119be19b64c9106c22f1779a10531f27b4ac6642268c94c564a1e5df09d9a9fdd8f8a99c7390576ef018fc926feb1161e7960bcaa61e17084bbbb2772e1636733f6392072351c1860281807099a4a77b8dcebbdde1cda705dd7ab51df0142ffd8f5c8587e40d54dfc3ee1bf180ecc3bbcb76ea19b9c71d62f88dcfa42faf2e078a9b08b2ccf0d6ad1079222f0889fd484906e4e43f41481d1af28d92783e0682dd6fc5b385a959f388954b3d70078c5607e42b87c9bf9c84d92b426e528c06fbdf3951ef95705d23131829b6951d41e8a5372cc4b51a9ff652f65722176b4005d65e4c128e6e9057dc65413f6a56a21f8d1d52589aae09a4b506a70f6b5049befcd8f167891f51d3065d83fde7e56019c82bd9957705c72fd0956a4b4f781fcfd7644814cf5a4ba71321387d9c96e83d67825ccd834218408fe811f0c5773a61b52c4b6c6676579e37821da49878deb96c73634045a139e8b91413d83238f523190dd62ee75e701270974bed7790eab81d813a63b485ff06a5ec83562de0c878c818808379c10b1ca9b120</script> <div class="hbe hbe-content"> <div class="hbe hbe-input hbe-input-default"> <input class="hbe hbe-input-field hbe-input-field-default" type="password" id="hbePass"> <label class="hbe hbe-input-label hbe-input-label-default" for="hbePass"> <span class="hbe hbe-input-label-content hbe-input-label-content-default">Hey, password is required here.</span> </label> </div> </div></div><script data-pjax src="/lib/hbe.js"></script><link href="/css/hbe.style.css" rel="stylesheet" type="text/css">]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>tendaAC8</title>
<link href="/article/cb6e4f2f.html"/>
<url>/article/cb6e4f2f.html</url>
<content type="html"><![CDATA[<div class="hbe hbe-container" id="hexo-blog-encrypt" data-wpm="Oh, this is an invalid password. Check and try again, please." data-whm="OOPS, these decrypted content may changed, but you can still have a look."> <script id="hbeData" type="hbeData" data-hmacdigest="42a43aff35738874d938f23d8de037bd219166ff2745668df2c5a0b46970995d">47d9635aef24c3f077639ffda1f136d7b8fafa3b280054f8fa6e5d0b9e782c5efa7d0ef548d0e5f9c7c3720be6911847342ee772f6d2e1936ef51432c48c84291740ab8c323ab76211ad2f54d82a1a51c06e9be75d507fb3d9bfd9dbbd77a79801b441f582310d2aa6a9b64cccdf78807afd5947ce02caea133c6acd1222aaa4d2ae89ed6ed5193b7129f8ff1592367f1b8b955d1d16816dad21fa413ca1441b25f89c19072c3c7803a2684f50c2d9a98af0771e79b0ae3aaec5a3bc5bbc86ec04065add4a9d8249db686bff7b6fc5800b771aa2e20484ed58055184098f897eed0dc1115bdecc36f9534fc2c202649fcfb9109d4a146badaff7d9d4c1e5c5db15ec56c85bd9ae77179ee36a435953a24f2794892616cc2bf3e5884566aa38195713a5ba6f4aa1aea814238d1f3c91ec71973e6bf7cf7a0ae24a6bb0bf9bb78ea313728b885c803b345744a5dd29043213551a100589fcbf867ee2280d65f0b8ff8e7384950c62e32a031e251c4cacc5173c11df8f25f2e3a694e149f9122ef75eee32dd114c32036a0d7967cf48fb67339312838173ed3e1bb58d7f5c1019c071db709990c9326750ba2c2bfb359c3056620caa1e45a6cf2a3f65b82de3b8c49deb83f15e866b82fcf5bc99b216f4a7a3c3b0b8f0f4f245a2f33d7b1c012932c0675e6a028232beb9c49707d947b58bc7fe81c609d1591627c01b626f55994b761f80f0dfe827157e043e31fd54aeb123c49f7269ae5ab89695c339b1bc9505fafe3a9ac465ce0d1897b9a41f074c76993f1ae384310431ce6624079bf6058b428107e1dbeb9984aa4806ef2d3f8e1a6df8ff9e842e1f9c58a8aa2908faa52fcb6cbb762f00d0de2a314b3c51a34ca9c75f10b4af0776a365732e100b911a2bd0ea37f8a0a0cfb6fab2a2e610e182c8ebe97f1c10917870e9b6dda02bb5ce67088795a11e4ba99f1932eaef17b6cdb29793ba2467dffea2c2eb36f8137325b72d8ea756b4905438c47a4d17bc507d70540c2a12bffe924d6a22de604d71dac653d92a2311ff13acf92539aa674307c92f9a2cffcc3b6ba9bd3a724bb944b8ded842098359700fa9a93c6105ed976a473593b28c756ea3b94ebcf519b4ade7fdfb348720e2815836b728d639912112c23e07f20cef213af332cd3fe540b846b9c3cd4f6bce712858e3b9f96b2099d92f605e7ec7abf4392dc5f77d699fc39c1c58bdbea4bed8ec6c2a12b00677df30ce1591ebc7693ced3d201dd60eab3e425016969cbf926ff6ecad99b3ea8cc68d331e3570b3ac4aabd0df092a87b66a838071dc17c13f1273e391e98332149874ad16018ba55ad663067996986f5109f3b2ec8547f88305103fd2027f0a0280bcd3c6277541e58081c853955f14ab4db76aaa1c7c38139d73c01e0306b25fc77e1f9555431d291ed4b7d1cf65b91065ed75872377959472b39140028ac5bdeacfa48da4daf5f634526cead59ecc80350de05708451bda8c88ab62e442f8162ad5bfb2a54fd7ad886e80da92adaf1de7021fe7cb54952dcde1e24616419813bed52055f537c8d0f4c33983f5644cc01973c8ced9243f89cc8680d70ad230317a0f84ed2bb85198d32bf7cd4154c47c335fc795a058af54072791ab4cd7c1c8071229487024bebede692512016b1e9659452498ed90b624ab8709ad85c302535625e715bf1fb66087a0c762fb73db339b853a504b747887878bae4d8d0d88065bf645d43e4a0ae85120b578ece99925dcc512128a7cac73bea9b3ce8c8b35e8a70c222ac1cbfba705bc1643872e5fbceb13520d616b921778025abc1392eaae01a3b5a3ea7af6d8139cdcd0ac46bd2392d6832b6257e6a80e831e89810e5fb15dffbd02e098cf05f1224e5be5a11479083c09aeaba6fca8d4a08089ff09cf78a7b913cc5cf462d01e3d7e2a10f6f636234689b6e05738754b39a75d4131b11009404a166c75f4d1f133e1a23e28eab2acb8aa40c4e8bd35211d32344f93a86350325307ce498e6ef8c4a9ea3cb83ece3b27c36dc26347e596ee9cbb899be3ba884817ce424821101378a912c9eeab9470e656b46ba53381233154c0220a97cef1521ca5cf5eac4c5d1234f71f8db8005c0e31d09f3e4f9cf0b907909b4a5d4ae8e8b50f31b9f393bf43a85d7f4234009c5ae14070077d4a9b8fdae1e1c60215107b5ccac04294fbdafb62e0304e89a321ead76b8a11760777e222883f0940470c5e50b2b5f3d467e6f0be448633e80cda878408f9e88f82bde7209d4f14ee38be97f23bb8b183d9af6db4a60a8ce77d8f1cd4be99022a5ada35d92936e7dc2b131a7d075d131a40dfb6a0d5db9862d0708694c30c0f6002f78dbf47561f9b27f165a843fe92d18febb0bfc0bf07d3a642951502b20abf549f50beab0d121689ff0c9abcbc76766f4252f4c908de81a4cddf00502928f2958511702764484d2a3d889ec40014a02d715fd9be038cebda0615565b5f9a974167e86c208fdb679e9e99c9c7e3b423a72e78dbb268c9ac2d78d5ecb6d9d15205e8632dcb53297cced6fac987237589166892b3c74fb9c1a8fc2768a90619d1f8a3710d909d9d3ca336a22950d25eb8326f586a25638624da2a51a5ad9c2e88d8b525e56c8d9644d36a6c120cad00e5090ddae46771cf973367ab2b86c83cd71a2fecbd36b4520d4dba17625b85c1aa775fc49846d61dfea6747cef7cc5b5d042108982a9e8af2d73fd8ae759d269170647e3ee91482ba4b57f842f59b04dc6d824e8dacac68bc7d52fecfdd2bc1dc2711b1222a420807017260eebe8969ab7b2ec8594a5f3a3e25b05ee6bdfc3fb0be693f94c573de24be4055e5866b4df42c2cb8ea3d41db5bb7de2f578ce67b2d48a5716f1c63a2b6914fad06735154738f97c31dc8a95f730c58a437d43755f65477bed9040782726ea0e0b6bea9f6a6397e1efb92b6e9cddff1132f57f12ca28320f8e97848b846a8bf08866a04bc0bf769023a4f63fb661c8259b45f524f515cf225ad804f23bcc66d2dead86326fc759f7356b40adf239f47c2d74b61c7e22b3af3c3e39a311a36cbcc734d35d4014ff2a369086c1a3e1df3b547652d470a2b86d47f486a689a1ff68aa69be5c2deb073eaa57fbd319d4bb6b64b274c460d88688464d31fdabdbd142d5f62f96211decbb074736b721cef2517c1db86f1747123bd2c4d07d22281ff56a3dca662ed5395b8ba58d7eb86bdefc472dd46ec0c3914b084048c26723d68e6863b2f0f0b49aa9ddd742bb12aada59c18dfc6c9e6f1286600f98a6cf16a49edd00f6de4667ede8c5145c700f528bbfa74e97dd072bcb8f3001692231b9c7ea047981e72820269739076f969b04ef904f7267079194bc8c07dd9d8fabc3456927d9a9ea6ec2bf26e26d613b20ae7bcb577f289698efecdb29b2e3855ceded077c191f458a25e6299e5390cdc43b23f897646e3dac0e80c2f573d396654fe6dd930a1d134bd0e3f2894221c91b021f27faf44d0accde751b53bf491a29dd97bf3342292ccae0ba39d3a17be54b51cdd3ce6639c08719fb10c82611e510c08d6e4f424f1b1ad3608af1a36dc275cada9c07de2770d1e605ffe5a25ffc4a18af541cbb4a882a5a719cd80c8c393c691ca748a73a0d530a481db47851b010be3c5fdeefb4816023da464486cc55b541c2b0a82eb86c47a19472678c02116050d9fe29664ad802c32d5efcfb962ed64346e4da6e653abb034e3959572294cff9ba48cb1c997f631336f4300ad00be822fef1e15e71771414d72f556213fa97dcf099600a7a38c99817d043f56d9e2a65af8b216b0e8751adb1b2e8ea0ffe1707575440df86f6f9777c0d5365c4175430e7f0a768a08d286a0749075ef5bd62c325f7ec8e5f48fb5403e411dc48d1c20b3ad75bf900b4161767a459b78a8176701e15f5218e27c1c843387e84fac398a94fd948f542bd632a3695ee652befee5a9511dcbd39b33bc56be8a2a97b4b20ef8480393504057e0ac0cbd230df8b83957946ce5827ce4ea147677bb40457c6d49d0ca77a5d5d3c30a81389fe28ce6774925195e140dd01d829247ddb758a1e0c657d061e9a79bdbe3b73f46d67749cc42f4f88bed68108a030cbed2c873b3de5e09924a445dd62b5a155aea00308d89809d49702adf1918f892c52cda18523976565b63cd2fe69fcc8450ea0ef93b76941ace552e3a79a287c3708d119c5f390f7f2be5cf5426b2921c182a9d71a16d8b53c88eaa6620d88a49d45e00f52167435a307a57c642b2d4db25904674fba23187a849a2fbeba3ae3683d1acde4bf6bddd169c23fb31287376b9a86815c8b9c37ff16a690d14931c657d8a202f2a9d00720b35a239ae8819e5f8459ebe687978ea5ea386504ac3f8711467e9c9616f67254d381f91e4fd717bce57fc1388a3515da2cdb9cf7c0bdfef626d1554bfdd448172979e20c756f735c1f0ab1b9bc897861ff8cdd2d76bf9474bfb07a28bdb814a89c90e53edf3a4318021697ecccbaaa7549240396fbc963f70ad8c48118bba4bf9c07cb14759b7002b51b0c434e154a3acccf08c0a8acc6dd9e74ba04d1297a7c3b6bacabc73f1f55843b682bee1f8a04f6c0ff6e3032bd502afa0a1cb8b553e7aac021a9a87d8b2a9b8ca3eb733396d09a863c79200393ca40a6ff720b6a4c7b34a1994e7e3b42cac101cb72fdfe5b7803cbd38a4a6edf2c9598562519fb6f5ba808e056a59e129bc6c826fea4354ca72c0b8498d6931a11c759687fb4b927c9f860e59e483d01232e9a59ffb984b674001bb8033b20c219885c580989daec84fe9157af7af0d0e70ab3fe512614135a58dc1b8a61d503e1bb17cd4e9344768e3166ef8a649411ed532efeefb32b4bec7fdf04c941a0994d4b01746a94345ee1ee46f4e85c06f540ab049ec8cd287f8e25adfd8f7ad0f8908eaa9e88d6d3d8dc0272f83aadd742921819ac418c53c81b34b56d9e9c1ec1c1cc4ff46126a70c96f7dacdf09e1f3aedee9cb3b4db999cd3ea8b1e2b4054c516082c261be20cb3dc009813b50b0b471e8907e5f8ba4e1b0d2e92536bc4989ea56c56d6ab4c7d3829918fc906cd7ef7646a9524ccaab9d7da00368cf8f6e48f452ba15d796c7fd8e52875e68661302dd204fcb8e324b04d9ea6ecfa627e06fa7f9460ca907a5e75ea733df1557fb569ece7e52d4033760a7809b6902044004b9eedb9a519819881fd7d97c87ef1ff48fc438ca7bce55e881216e2af4f91082a6bec69c43bbe5f7c637b647ab71fdc6dd5659a43b603b8b1f37ae346b386046950a46e78a5e6496af87c49f830e4a85a76237fa89cf84842852205caa138c597950c00f17b7a46c6c51dccedc2558153f657daade12788c62530ec6bef58c332f573c903d5d1f88da44cae1269098685601d626f93893d3a9dda3e0988ab5d6616b37c168eff5cc20717f63e57116ea6c2fe6cc86df9a125390d630e82b7bce0bcc62053e1eec316580b8bb5828f3449dfba9f456c4953ad5855ff883e9cc8fd6da201b92e804a2a9723e2abd959fb367720543cce97d1de1ecd84dbed1a0f421f50e4c231ba38ae03ff946229c835ddc00fd383fd039e3d2a120071668e809763343203376937f0e6c47ac408d8f2f2a42cc077030dbb9a21d4a2afc63293f030ff95f9b8722a7235aebf297050fa59a0679f6176f34dabf2407a57fe3aea7c992d5783ab2f56efed44d710126300874c69f214a4597753b19eecd2d9c36da6a9a0faac0110c84b68338edf2e53805ef9067a771df7bf248b8f1c2a26eaa3806793c9d07f721ca0cbe70eaaf76a14ea4098ebc50ee578f646e3c879d3b5d9a28f67ae45e37cea576d11fd76291606a8c3b67540dd0be13f5e39ae808212118d9d97407d76057011a3784424e39a2c9be2efe2caae05f30d28fac0cec324087f364dd75d87406fe0c7b29bf9c8be22e22d42cbc7ceffac2dd7ab8a4ed178dc8e8e0950b78749b9f458672d3c92315a5d2f82e0b981a0a503f31f570fb37893372b5eb415726e3a2ce3175f1de2a8dc3a0418379a407b0052edb7c8669553789ea1929a31e04a576f956a29b3835bc1a162972773d47a8005f8e17a1823f631b9b88bf163d6b8f97315462f09c40fa7aa789526d6174841085127fab69c5ac404d50b7a246ced77da5382ca5422b205f2e9df354a5966ae581057fccd78737d5057900796ff8730fdbe2460711593e6798dde5cde7704587d22fe5f31b77e60f06856b9468a380325f7ec6189ede78ee0a4e971a67673e02990f15ce0095cd7a18bca7b17e9ee9af76046ec15269291409d2e25469507d6343f370dd57909bca33cf7f5fc8524303264bc1adfb847ca18be6e4abbd7e2c8c3de30c232d569911deb2ed8cf33e19f93b6ed6af6cf69a4b8b33ffdc276ddb3d1a0b378a040a86221d26ac7ed92cded4c7e5e58f904d23d8d9110c110c3dfc281239c10930b6c1d1734e6e1978ccc46a8c0af6f3b88960ea7374e639b1802c5fc359c35a30fe6adb2d9dd8af5f9171145114c1d61289a835ea64ae5c31168c1fa080b0560213c27a52bbeef3565fc6883483cdefaa2aaf6863bd4c1fd2a921cc1221b48a0173094cea2506b4b1fbe5a74df8d7ee43a766ef0cd75a361ac0018bc37d6d6c904e6d30492d22aaa3041991154fc31867e7ccb00194b9cf951cb5d0a4784c07c6de27aa899535a0b180b14cfb0571cd7bb28308403b696a44121925dcfcef6236238dc16322de2ad462d996ef3baf9eb5292483f398ea3ec4825ece2c03e64b4903e005022ff274124e7c14e45b72e7e091b6f6206ac2266fb9ca26ecf7a7d4553fd2eed7279fd6a37c1060951607654149c629b695e250e0b0cfcb5c225951925f88b84c7d3053d5821912424ea56b22319526a4fa03531d82c7ca5ec637c8c2e4948827a7f1087e90cfd500a97ad9d30defba1951ef7052e88f299033b62439c6f2f91d6a3231df2fe7ba70851bba2d02d7e8d176979da8ea79100b84e809a3779f2e007e455122852837498debae849a9bb3e1c6d10c7e0e6c484e253a6d485fa7927522512a6e7167e172acbe60f70fdae6af4ad79f2b08e8ea8880e7e425aab06ddb7a15ee733485ac2226a1889312db68f1062aa6144ebd7200d495c7fb362e83f020594e86cce2dee29957f4629d88a06f9253ec6e63e97e8d3109b7310414837e4eeafa092b12fd5e41253aef26b0ad2e41467fb3a8d89cc40b5dbd6bc50e1687b6dfc8f269d1b8b6b98e478d48493820508e846e807d4bd7a6a1e2592bffff30cf4858e0358a2b8031813af1daa4143dd845c96744c55e255043130021513579d6ebcb103e78a61efae1d480d366e5b153d1467cfe52a4540958f51c89e5ac2474f1785ea75e75f946b77e895a23593f9b3edafb82fbcd95135216d7f6cd28a056f955fde07309dc3a870b1a8e58823d2da59a98c4a81dcc4dc71d2e5e99000d2166645e9030d04fb1b4660758747e9c6a47d7bfedf0f3439397fe7f1f0630399fbcb3cc17854b9776e72c90e835b0ce3e95c34479c361a6cf04362c9364161684c756d66560bcd61d641e0f517768542b993a33d1871c526c3c2fa3238310e221453fb848d615354a64f5d0d26c7596d2f603b3e26765f1430e0a011186e035c8faf7791b5068ec2c0d47f8352eeabc0ab8e6fb593a6998971f945f88d1d453b466f2480f233961c0be932a485807089c4ab2d82e1e33bae95a9f2ba59e100095db3b862dc3aeef7477f15b4acf4092e14d4e3c37652a52f38c7849f0c88089e0921fea817db7c03221b9966c4d20715562a38efa5796a03647835665a059a641b2550679bb0f9fb72d270c7f0bc8c825338c3d81509dc1b2933d0cf007604723aa907735734f4118c7c7d2d41aa204674a47fa5f4bd815ae297af8044c12188314f0674b196cccf50d13088c44a50a11c26e9040bc9c5229527d9942314be432c9a9be5777f1d917e74c8180d168533d83bac94c81703229b7127d5eff3d97bebeaa518f1128c0c790e5d7ffd2d1e22cf37fe8641e3fab636ce80eb39c96ef39b3bf2ead8da0ec3d816bc9dfa42ffb99e136e1a4a5ac19f370399b2d0fcfad988d152c38716181526b0c13a4628ffcf6dc266336c52bc785619b5c3718b7debc32a166368054c0fa53450f00f4e2c82d70cfff94e56062c2accee14388cde983e55c294ab17785eb5e427e74028dca8baa9f35c11102905d6bd0f7a0cc8ae6f547f2f914afe39b8b630bf2410abf0beda4991b81494e97c0eb0ac43370cd7bf23de5330dd125901eea5691719f68f6e82caf708712dc646ce786ac873f50b945456467c68061fd952b547cc46f062b2b2db75a31c45bbfce718cc0ab751c1b41e3f838fdd1d1c70662fa7887ecc07b56f35bd988339be3e1f74c21f277d19853fd773ce96d0ee638c425bdbfcfa8ee4e380391fcd752402df3275b150c9215f774e3a4edc59f4c5f89f26d7e7883cabb5bd744b67cba6aa92ca2a45697862a4450da6794f7403a60caff2db5c6c6f7e05fd3bcd6b7eab6f014b5f39ab9ae993d5fadecf6b33fdc23bbbfd9fc3f45629342eed65528c7b3875f782dd96bfb222f465a5b70166ae126bf1921648e4bc5030b2a010187254e8aa29573dbe5db0841f316107e801d78f5c0721e38f8509333d5411282900abeb4ed8f75b4536b07b5dee2b2094a45861bb3b6be26da833d389b1a1fff881232917ab23951ee0a184d93937de0705e70133a609179f410876bc6132c123d49165f009990dd163206368b341aa31272a2713e9914bfe48df900cbe14f6dcfc692c35a10a48ca247eafe9f6de2e556ae2822f348bc69cd1181b270f3433f988c136d2cfd23734bff5c579e38168c989ba75bb96a72baa18c480312db82d718e65fb7cc7b5ef2c23b7c689c853c6006a9fb90a3a486fb56f3365c06dc2d92a201cbf129bf112cf0500075b08df1766e6d724edab90482251bb48f33a100af5f8b8e26333724b4662215bfe174cda355113b6ba7b5db4060285c742c9ba5166025eca1ad9ff3aee5c1f676d5603ca377b0854c37dee6359a455353a0867f562c2e8190c80d5ba9d03fec87333ebb4a47c60f2d1cc7f1e4aa31e75d46aa021283b53bf766471d295c02fad0ff94d2ba0fe84a832ed319150297e90c453dc3170ba64a5d1bb2fe12fb8839c10980f604b892b306bd3f36cb908d96f090293c6e3a9faec1d0eaca5c400d844566419c48b96b2e6913b</script> <div class="hbe hbe-content"> <div class="hbe hbe-input hbe-input-default"> <input class="hbe hbe-input-field hbe-input-field-default" type="password" id="hbePass"> <label class="hbe hbe-input-label hbe-input-label-default" for="hbePass"> <span class="hbe hbe-input-label-content hbe-input-label-content-default">Hey, password is required here.</span> </label> </div> </div></div><script data-pjax src="/lib/hbe.js"></script><link href="/css/hbe.style.css" rel="stylesheet" type="text/css">]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>tendacp3</title>
<link href="/article/e3065a82.html"/>
<url>/article/e3065a82.html</url>
<content type="html"><![CDATA[<p>这里就先不放设备照片了,诸位可以自己在该页面寻找下设备型号。</p><p>这款路由器是通过云端进行数据传输的,即 摄像头 = 云端 = 手机,无web页面,且并未发现摄像头与手机直接通信。</p><h2 id="摄像头"><a href="#摄像头" class="headerlink" title="摄像头"></a>摄像头</h2><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/IMG_0338.jpeg" alt="IMG_0338"></p><p>前边这个黄色印字的pcb我并没有查出来具体是做什么的,但是我看这个设备介绍是有高清夜视能力的,我猜是这么个功能,不重要。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220715093743157.png" alt="image-20220715093743157"></p><p>使用了上海富瀚的FH8626V100,下面是各种文档,详细文档我没找到。</p><blockquote><p><a href="https://www.fullhan.com/index.php?c=article&id=221">https://www.fullhan.com/index.php?c=article&id=221</a></p><p><a href="https://www.fullhan.com/uploads/2021/11/163669725327888.pdf">https://www.fullhan.com/uploads/2021/11/163669725327888.pdf</a></p><p><a href="https://blog.csdn.net/xue_nuo/article/details/125717256?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_title~default-0-125717256-blog-122374192.pc_relevant_multi_platform_whitelistv2&spm=1001.2101.3001.4242.1&utm_relevant_index=3">https://blog.csdn.net/xue_nuo/article/details/125717256?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_title~default-0-125717256-blog-122374192.pc_relevant_multi_platform_whitelistv2&spm=1001.2101.3001.4242.1&utm_relevant_index=3</a></p><p><a href="https://blog.csdn.net/xue_nuo/article/details/122374192">https://blog.csdn.net/xue_nuo/article/details/122374192</a></p></blockquote><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/IMG_0371.jpeg" alt="IMG_0371"></p><p>flash 为H25S64,从查出来的资料来看是8m的,很遗憾的是我的ch341a并不支持这个型号的闪存,所以提取写入固件操作也办不到。</p><p>只能吧信息放到这了,原谅我硬件知识的匮乏。</p><h2 id="固件"><a href="#固件" class="headerlink" title="固件"></a>固件</h2><p>这里因为flash型号的问题我没办法从固件提取,但是官网可以直接获取,且并没有加密。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220715102403033.png" alt="image-20220715102403033"></p><p>squashfs 文件系统,但解包出来的文件系统在cpio文件中。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220715110812734.png" alt="image-20220715110812734"></p><p>但涉及到一部分的文件还是在squashfs-root中</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220715111032612.png" alt="image-20220715111032612"></p><p>只有一个root账户默认开启。密码并没有爆破出来。</p><p>通过rcS文件的分析和对uart的输出信息来看,主要为两个服务 noodles 和apollo。后边会有分析。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220715113120175.png" alt="image-20220715113120175"></p><p>文件格式为32位arm小端序</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220715112602198.png" alt="image-20220715112602198"></p><h2 id="uart"><a href="#uart" class="headerlink" title="uart"></a>uart</h2><p>该设备有uart接口,并且将每个用处都标注出来了。但是是被堵上的,需要将杜邦线焊接上去。</p><p>(请忽略我的焊接技术,我真没学过)</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/IMG_0342.jpeg" alt="IMG_0342"></p><p>波特率为115200,tenda好多设备都都是这个。</p><p>下面是通过打印获取到的一些信息。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220715143628881.png" alt="image-20220715143628881"></p><p>这里理论上摁E可以不使用自动启动,但我没有成功。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220715144742789.png" alt="image-20220715144742789"></p><p>linux内核</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220715145126558.png" alt="image-20220715145126558"></p><p>可以看到cpu相关的sdk。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220715145228397.png" alt="image-20220715145228397"></p><p>两个服务的启动。noodles 和 apollo,前面提到过</p><p>noodles监听了1300端口,但我并没有找到任何关于这个服务的相关信息。</p><p>apollo应该是apache apollo服务</p><blockquote><p>Apache Apollo是一个代理服务器,其是在ActiveMQ基础上发展而来的,可以支持STOMP, AMQP, MQTT, Openwire, SSL, and WebSockets 等多种协议。</p><p><a href="https://www.freesion.com/article/41891296353/">https://www.freesion.com/article/41891296353/</a></p></blockquote><p>之后尝试逆向分析。</p><hr><p>上次的坑来填了</p><p>之前没有系统学习过网络编程,花了一周时间把tinyhttpd的源代码阅读理解了一下,并且仿照用python写了一个简易的httpd,可以看我另一篇文章</p><h2 id="noodles服务分析"><a href="#noodles服务分析" class="headerlink" title="noodles服务分析"></a>noodles服务分析</h2><p>通过分析发现noodles监听了1300端口</p><h3 id="启动"><a href="#启动" class="headerlink" title="启动"></a>启动</h3><blockquote><p>sudo chroot . ./qemu-arm-static ./usr/bin/noodles</p></blockquote><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220825143728754.png" alt="image-20220825143728754"></p><p>可以使用nmap来查看是否监听1300</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220825143906273.png" alt="image-20220825143906273"></p><p>可以看到1300端口已开放,并且noodles也对nmap有反应了</p><h3 id="静态分析"><a href="#静态分析" class="headerlink" title="静态分析"></a>静态分析</h3><p>对于程序的静态分析,可以从main函数来正向递进分析,也可以从一些字符串来分析,又或者从一些关键函数</p><p>这里通过nmap扫描时noodles的打印来查找</p><p>通过交叉引用发现在FUN_00011878函数中存在相关信息。</p><p>创建并监听1300端口</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301301108367.png" alt="image-20220825152959870"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301301108369.png" alt="image-20220825154343089"></p><p>等待用户连接</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301301108456.png" alt="image-20220825153205132"></p><p>获取client传进来的内容</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301301108183.png" alt="image-20220825153844262"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301301108672.png" alt="image-20220825154440079"></p><p>主要内容处理在下面相似的内容处</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301301108224.png" alt="image-20220825155349794"></p><p>1300端口大概做了这些事情</p><p>参数有一下几种</p><blockquote><p>UPGRADE</p><p>BURNMAC</p><p>ELFEXEC</p><p>SYSTEM</p><p>SYSTEMEX</p><p>DOWNLOAD</p><p>UPLOAD</p><p>FLASHDUMP</p><p>BURNSN</p><p>READSN</p><p>WRITEENV</p><p>READENV</p></blockquote><h4 id="fun-00014f90-函数"><a href="#fun-00014f90-函数" class="headerlink" title="fun_00014f90()函数"></a>fun_00014f90()函数</h4><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301301108708.png" alt="image-20220826095918427"></p><p>三个参数分别为从client传入的内容,字符串,0</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301301108283.png" alt="image-20220826101125979"></p><p>这里是xml参数处理。</p><h3 id="成果"><a href="#成果" class="headerlink" title="成果"></a>成果</h3><p>这里出了一个代码注入和一个设备重启</p><h4 id="设备重启"><a href="#设备重启" class="headerlink" title="设备重启"></a>设备重启</h4><p>设备重启是利用了代码问题,更像是设计时不严谨导致的</p><p>当标签中含有upgrade时,会运行到FUN_000146f4函数,执行完毕后必然会执行到FUN_00016b90函数来使设备重启。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301301108749.png" alt="image-20220826093937746"></p><p>只需要运行到此处,脚本会使设备重启</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301301108256.png" alt="image-20220826093948721"></p><p>poc</p><div class="code-wrapper"><pre><code class="hljs python"><span class="hljs-keyword">import</span> socket<span class="hljs-keyword">import</span> times = socket.socket(socket.AF_INET,socket.SOCK_STREAM)s.connect((<span class="hljs-string">'127.0.0.1'</span>,<span class="hljs-number">1300</span>))s.send(<span class="hljs-string">"<UPGRADE>test</UPGRADE>"</span>.encode())<span class="hljs-built_in">print</span>(s.recv(<span class="hljs-number">1024</span>))s.close()</code></pre></div><h4 id="代码注入"><a href="#代码注入" class="headerlink" title="代码注入"></a>代码注入</h4><p>这里更像一个后门,直接在 FUN_000140b4函数中发现,如果<code><system></system></code>中的参数不是iwlist便会直接使用system执行</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301301108353.png" alt="image-20220826095120280"></p>]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>协议-低功耗蓝牙协议(BLE)</title>
<link href="/article/94a01627.html"/>
<url>/article/94a01627.html</url>
<content type="html"><![CDATA[<h1 id="蓝牙"><a href="#蓝牙" class="headerlink" title="蓝牙"></a>蓝牙</h1><p>蓝牙是一种近距离无线通信技术,运行在2.4GHz免费频段,目前已大量应用于各种移动终端,物联网,健康医疗,智能家居等行业。</p><p>低功耗蓝牙协议是由蓝牙技术联盟(Bluetooth SIG)在2010年发布的蓝牙4.0,并不是蓝牙3.0的升级,而是全新的技术架构。</p><p>蓝牙4.0版本分为两种模式,单模蓝牙和双模蓝牙。</p><p>双模蓝牙,支持低功耗蓝牙的同时还兼容经典蓝牙,经典蓝牙的特点是大数据高速率,例如音频、视频等数据传输,常见的蓝牙音箱就是双模蓝牙,他需要大量的音频数据传输。</p><p>单模蓝牙,即低功耗蓝牙模式,是蓝牙4.0中的重点技术,低功耗,快连接,长距离。像各种手环,蓝牙温度计等都属于单模蓝牙。</p><h1 id="低功耗蓝牙"><a href="#低功耗蓝牙" class="headerlink" title="低功耗蓝牙"></a>低功耗蓝牙</h1><p>目前低功耗蓝牙在移动终端,智能家居,互联设备等市场都有广泛应用。</p><p>其优点:</p><ul><li>低功耗,使用纽扣电池就可以运行数月至数年。</li><li>快连接,毫秒级的连接速度,传统蓝牙甚至长达数分钟。</li><li>远距离,长达数百米的通信距离,而传统蓝牙通常10米左右。</li></ul><p>蓝牙联盟为低功耗蓝牙定义了一些标准数据规范(profile),只要遵守该规范,任意厂家的蓝牙设备,均可以相互连接与通信,例如无线蓝牙键盘鼠标,无论是安卓或是iOS还是Windows,均是即插即用,这便是“标准”的力量。</p><p>低功耗蓝牙支持的标准Profile有:</p><ul><li>HID,用于无线鼠标,键盘或其他遥控设备。</li><li>BatteryServices,电池状态服务,用于告知电池电量状态。</li><li>HRP,心率计Profile,用于心率采集。等等。</li></ul><p>低功耗蓝牙还可以自定义Profile,伴随着智能手机的发展和普及,低功耗蓝牙的这个特性得到了发扬光大,同时也拓宽了低功耗蓝牙的应用领域。例如,可以自定义一个开关量的Profile,数据01表示开灯,数据00表示关灯,然后手机发送数据01和00就可以控制灯的亮和灭。</p><p>类似的应用案例有很多,下面总结应用特点:</p><ul><li>支持自定义Profile,可以收发任意格式的数据,如01和00。</li><li>支持自定义设备,支持任意设备的连接和通信,例如智能蓝牙插座等。</li></ul><h1 id="工作流程"><a href="#工作流程" class="headerlink" title="工作流程"></a>工作流程</h1><p>以下将低功耗蓝牙统称为BLE,低功耗蓝牙设备称为BLE设备。</p><h2 id="角色"><a href="#角色" class="headerlink" title="角色"></a>角色</h2><p>BLE设备角色主要分为两种角色,<code>主机(Master)</code>和<code>从机(Peripheral)</code>,当主机和从机建立连接之后才能相互收发数据。</p><ul><li>主机,主机可以发起对从机的扫描连接。例如手机,通常作为BLE的主机设备。</li><li>从机,从机只能广播并等待主机的连接。例如智能手环,是作为BLE的从机设备。</li></ul><p>另外还有<code>观察者(Observer)</code>和<code>广播者(Broadcaster)</code>,这两种角色不常使用,但也十分有用,例如苹果的iBeacon,就是使用广播者角色来做,只需要广播特定内容即可。</p><blockquote><p>iBeacon,苹果公司开发的一种通过低功耗蓝牙技术进行一个十分精确的微定位技术;</p></blockquote><ul><li>观察者,观察者角色监听空中的广播事件,和主机唯一的区别是不能发起连接,只能持续扫描从机。</li><li>广播者,广播者可以持续广播信息,和从机的唯一区别是不能被主机连接,只能广播数据</li></ul><p>蓝牙协议栈没有限制设备的角色范围,同一个BLE设备,可以作为主机,也可以作为从机,我们称之为主从一体,主从一体的好处是,每个BLE设备都是对等的,可以发起连接,也可以被别人连接,更加实用。</p><h2 id="广播"><a href="#广播" class="headerlink" title="广播"></a>广播</h2><p>一个智能手环,在绑定之前,需要让手机发现自己才能去进行绑定操作。</p><p>这个让手机发现自己的操作就叫做广播。</p><p>即从机每经过一个时间间隔发送一次<code>广播数据包</code>,这个时间间隔称为<code>广播间隔</code>,这个广播动作叫做<code>广播事件</code>,只有当从机处于广播状态时,主机才能发现该从机。</p><p>BLE设备拥有40个信道,从0到39,其中37,38,39就是BLE的广播信道。</p><p>在每个广播事件中,广播包会分别在37,38和39三个信道上依次广播。</p><p>广播时间间隔的范围是从20ms到10.24s,广播间隔影响建立连接的时间。广播间隔越大,连接的时间越长。</p><p>广播数据包最多能携带31个字节的数据,一般包含可读的设备名称,设备是否可连接等信息。</p><p>当主机收到从机广播的数据包后,它可以再发送获取更多数据包的请求,这个时候从机将广播<code>扫描回应</code>数据包,扫描回应数据包和广播包一样,可以携带31个字节的数据,如果长度不足,会补0,这部分数据无意义。</p><blockquote><p>提示:蓝牙4.x,广播有效载荷最多是31个字节。而在蓝牙5.0中,通过添加额外的广播信道和新的广播PDU,将有效载荷增加到了255个字节</p></blockquote><p>在安卓手机中可以使用BLE调试助手来查看广播包。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111025384.jpg" alt="0A3834EF258FD440B5A62DAF533A5AB9"></p><p>广播包一般格式为 0x长度类型数据长度类型数据…</p><p>0x02011A05030F1892FD11094544494649455220545753312050726F</p><p>这是我附近某个耳机的广播信息。</p><p>分析:</p><ul><li>0x02/01/1A05,长度2/类型/对应长度的值。</li><li>0x03/0F/1892FD,长度3/类型/对应长度的值。</li><li>0x11/09/4544494649455220545753312050726F,长度16/类型/对应的值。</li></ul><p>前两段数据并不能看出什么信息,第三段数据可以转为ascii看一下。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111026149.png" alt="image-20230106111344806"></p><p>即蓝牙耳机名字。</p><h2 id="扫描"><a href="#扫描" class="headerlink" title="扫描"></a>扫描</h2><p>扫描是主机监听从机广播数据包和发送扫描请求的过程,主机通过扫描,可以获取到从机的广播包以及扫描回应数据包,主机可以对已扫描到的从机设备发起连接请求,从而连接从机设备并通信。</p><p>扫描动作有两个比较重要的时间参数:<code>扫描窗口</code>和<code>扫描间隔</code>,如果扫描窗口等于扫描间隔,那么主机将一直处于扫描状态之中,持续监听从机广播包。</p><p><a href="http://doc.iotxx.com/%E6%96%87%E4%BB%B6:BLE%E6%8A%80%E6%9C%AF_%E6%89%AB%E6%8F%8F%E7%AA%97%E5%8F%A3%E5%92%8C%E6%89%AB%E6%8F%8F%E9%97%B4%E9%9A%94.jpg"><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111026362.jpg" alt="BLE技术 扫描窗口和扫描间隔.jpg"></a></p><ul><li>被动扫描,主机监听广播信道的数据,当接收到广播包时,协议栈将向上层(也就是应用层,用户可编程)传递广播包。</li><li>主动扫描,主动扫描除了完成被动扫描的动作外,还会向从机发送一个扫描请求,从机收到该请求时,会再次发送一个称作<code>扫描回应</code>的广播包。</li></ul><h2 id="连接"><a href="#连接" class="headerlink" title="连接"></a>连接</h2><p>除了扫描, 设备也可以主动发起连接, 发起状态的设备和扫描状态的设备区别在于:当它监听到一个可连接的广播, 发起设备就会发送一个连接请求, 而扫描设备会发送一个扫描请求。连接请求包括一套为从设备准备的连接参数, 安排连接期间发生的通道和时间。如果广播设备接收了连接, 两个设备会进入连接状态, 发起方会称为 Master(主机),而广播方会称为 Slave(从机)。</p><p>所有的通信都发生在两个设备的连接事件期间, 连接事件周期的发生, 按照连接参数指定的间隔联系, 每个事件发生在某个数据通道(0~36), 调频增量参数决定了下次连接时间发生的通道, 在每个连接时间期间, Master 先发送, Slave 会在 150us 之后做出回应, 即使一个连接事件发生( 或两者), 双方都没有数据发送(例外情况是从设备潜伏使能), 这允许两个设备都承认对方仍然存在并保持活跃的连接。</p><p>主机和从机都可以主动断开连接。一边发起断开, 另一边必须在断开连接之前回应这个断开请求。</p><h2 id="通信"><a href="#通信" class="headerlink" title="通信"></a>通信</h2><p>BLE 通信的两个基本概念。</p><ul><li><strong>GAP</strong> 通用访问配置文件(Generic Access Profile)</li><li><strong>GATT</strong> 通用属性配置文件(Generic Attribute Protocol)</li></ul><p>GAP完成了上面广播,连接的操作。</p><p>GATT则定义了两个 BLE 设备连接后如何使用服务和属性两个概念进行数据交换。</p><p>GATT 的两个主要概念:</p><ul><li>服务(Services)</li><li>特征(Characteristics)</li></ul><p><code>Profile</code>包含一个或者多个<code>服务</code>,每个<code>服务</code>又包含一个或者多个<code>特征</code>。主机可以发现和获取从机的<code>服务</code>和<code>特征</code>,然后与之通信。<code>特征</code>是主从通信的最小单元。</p><p>每个服务和特征都有自己的唯一标识<code>UUID</code>,标准UUID为128位,蓝牙协议栈中一般采用16位,也就是两个字节的UUID格式。</p><p>每个特征都有自己的属性,属性的取值有:<code>可读 Read</code>,<code>可写 Write</code> 以及 <code>通知 Notify</code>。</p><p>这样,两个BLE设备就有以下的数据交互方式。</p><ul><li>主机可主动向从机Write写入或Read读取数据。</li><li>从机可主动向主机Notify通知数据。</li></ul><h2 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h2><p>这里使用了两台手机来模拟两个BLE设备</p><p>从机:</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111026174.png" alt="image-20230109174401933"></p><p>主机连接从机:</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111026650.png" alt="Screenshot_20230110-143857"></p><p>上面链接后可以看到整个profile,下面每个UUID对应一个服务,不同服务之间有不同的特征。在UUID为 0xFFF0的服务中,有三个特征,0xFFF1,0xFFF2,0xFFF3。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111026460.png" alt="image-20230111094129656"></p><p>可以看到FFF1的属性为read/notify,可读,通知。FFF2的属性为Write,可写。</p><p>从机页面中,从机通过0xfff1发送数据。0xfff2接收数据。</p><h3 id="0xfff1"><a href="#0xfff1" class="headerlink" title="0xfff1"></a>0xfff1</h3><p>从机发送数据:</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111026344.png" alt="image-20230111094259820"></p><p>主机实时接收:</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111027574.png" alt="image-20230111094737409"></p><h3 id="0xfff2"><a href="#0xfff2" class="headerlink" title="0xfff2"></a>0xfff2</h3><p>主机发送数据:</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111027280.png" alt="image-20230111095031034"></p><p>从机实时接收:</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111027889.png" alt="image-20230111095106285"></p><h1 id="嗅探"><a href="#嗅探" class="headerlink" title="嗅探"></a>嗅探</h1><p>可以理解为利用窃听装置来获取双方通信内容。</p><p>ble设备功能设计中,一定会少不了私有的Service或Characteristic,就要通过app逆向或嗅探蓝牙通信来分析了。</p><p>蓝牙嗅探最好的神器是Ubertooth One,精致的硬件+配套的软件变成了物联网黑客强大的帮手。</p><blockquote><p>这玩意挺贵的,贵不是他的缺点,是我的缺点。</p></blockquote><p>所以我们使用暂时使用廉价的替代方案,BLE USB Dongle。之后有设备后会配套更新相应文章。</p><blockquote><p>这玩意只支持ble</p></blockquote><p>这里使用的是一块nRF52832 Dongle,某宝可以直接买到烧录好的板子,具体烧录过程就不赘述。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111046396.jpg" alt="image-20230111104642738"></p><p>具体可看官方文档:<a href="https://www.nordicsemi.com/Products">https://www.nordicsemi.com/Products</a></p><h2 id="配置wireshark"><a href="#配置wireshark" class="headerlink" title="配置wireshark"></a>配置wireshark</h2><p>购买板子后找客服要来物料包,其中包含相关插件。</p><p>打开 wireshark → 帮助 → 关于 wireshark → 文件夹 → 双击打开 Extcap 路径(全 局路径和个人路径二选其一)如下图所示:</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111027258.png" alt="image-20230111101431156"></p><p>将 extcap 文件夹的四个文件复制到 wireshark 的 extcap 路径下, 以全局路径为例,如图所示:</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111027128.png" alt="image-20230111101537140"></p><p>双击 wireshark 个人配置的路径,如图:</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111027355.png" alt="image-20230111101655494"></p><p>在弹出的文件夹中打开 profiles 文件夹</p><p>将解压压缩包的 Profile_nRF_Sniffer_xx_xx 文件夹拷贝到 profiles 文件夹中,如图:</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111027834.png" alt="image-20230111101728559"></p><h2 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h2><p>软件配置成功后,将设备 插入 USB 口连接至 PC 端,打开 Wireshark,选 择 nRF sniffer COMx,具体串口号根据实际选择。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111027932.png" alt="image-20230111101925074"></p><p>在工具栏中选择 → 视图 → 接口工具栏 → nRF sniffer,会出现如下界面(默认抓取 所有 BLE 广播信号):</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111028268.png" alt="image-20230111101959670"></p><p>选择任一 BLE 从机上电进行广播。 </p><p>抓取指定 MAC 地址设备的数据包。</p><p>可通过 APP 查看设备 MAC 地址,如下图所示:</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111028533.png" alt="image-20230111102043707"></p><p>如下图红色方框中所示,点击 devices 过滤下拉框选择对应 MAC 地址的 device,选择 固定设备后则只会抓取和该设备有关的数据包。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111028931.png" alt="image-20230111102101560"></p><p>Wireshark 选择该 MAC 地址设备后,该设备的广播包、scan request packet 和 scan response packet 都会被捕获到。</p><p>![image-20230111102119282](/Users/pipi/Library/Application Support/typora-user-images/image-20230111102119282.png)</p><p>该设备与任意 master 通信的数据包都可以被抓取,包括连接过程和连接之后的数据 包。双击任意一个 packet 可查看具体内容,例如该设备广播包抓取内容如下:</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111028239.png" alt="image-20230111102137695"></p><h1 id="Hello-World"><a href="#Hello-World" class="headerlink" title="Hello World"></a>Hello World</h1><p>其实是对一个简单的蓝牙氛围灯的嗅探与攻击,其功能比较简单且无数据加密。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111052210.jpg" alt="image-20230111105207086"></p><p>app长这样</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111144377.jpeg" alt="IMG_2E60123242CF-1"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111144425.jpeg" alt="IMG_82B5E06A322C-1"></p><h2 id="分析"><a href="#分析" class="headerlink" title="分析"></a>分析</h2><p>使用wireshark来嗅探相关信息。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111111065.png" alt="image-20230111111111938"></p><p>使用手机app连接灯。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111116973.png" alt="image-20230111111617864"></p><p>有很多Empty PDU空包,使用 !(btle.data_header.llid == 0x1) 来过滤</p><h3 id="开关"><a href="#开关" class="headerlink" title="开关"></a>开关</h3><p>从手机发送打开命令</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111123878.png" alt="image-20230111112358755"></p><p>其对0x000e特征发送了bc01010155</p><p>关闭命令</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111126880.png" alt="image-20230111112654746"></p><p>对0x000e特征发送了bc01010055</p><p>通过对比,第5位的01/00控制灯的打开和关闭。</p><h3 id="改变速度"><a href="#改变速度" class="headerlink" title="改变速度"></a>改变速度</h3><p>该灯可以调节灯块闪烁速度。从0-100</p><p>修改为0</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111132736.png" alt="image-20230111113239663"></p><p>修改为100</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111138001.png" alt="image-20230111113830782"></p><p>对比第四位从00-64转换为10进制,即0-100</p><p>所以通过修改该参数可控制速度。</p><p>bc0801 00 55</p><h3 id="改变灵敏度"><a href="#改变灵敏度" class="headerlink" title="改变灵敏度"></a>改变灵敏度</h3><p>与速度类似</p><p>修改为0</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111145004.png" alt="image-20230111114518816"></p><p>修改为100</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111145706.png" alt="image-20230111114553528"></p><p>特征与速度类似</p><h3 id="改变模式"><a href="#改变模式" class="headerlink" title="改变模式"></a>改变模式</h3><p>第一个模式</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111147071.png" alt="image-20230111114710947"></p><p>最后一个模式</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111147434.png" alt="image-20230111114739307"></p><p>所以模式从01-99共153个。</p><p>bc060200 01 55</p><h3 id="改变颜色"><a href="#改变颜色" class="headerlink" title="改变颜色"></a>改变颜色</h3><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111150198.png" alt="image-20230111115025067"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111151788.png" alt="image-20230111115131681"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111152383.png" alt="image-20230111115200253"></p><p>通过对多个颜色的分析,数据格式应该为bc04060 11c 0 196 000055,其中11c控制亮度,196控制颜色。</p><p>通过上面的分析,发现都是通过0x000e来进行操作。</p><h1 id="攻击"><a href="#攻击" class="headerlink" title="攻击"></a>攻击</h1><p>这里利用linux蓝牙栈(blueZ)来操作。</p><blockquote><p>sudo apt-get install bluez</p></blockquote><p>安装完成后会有hcitool和gatttool两个工具,分别进行扫描和连接以及数据的读写。</p><p>硬件使用一个蓝牙4.0的免驱适配器。</p><p>如果你的电脑虚拟机无法获取到主机网卡,可以在vm设置中取消与linux共享蓝牙设备,再接入外接适配器。</p><h2 id="hciconfig"><a href="#hciconfig" class="headerlink" title="hciconfig"></a>hciconfig</h2><p>用于配置蓝牙设备。我们可以运行这个命令来列出连接到我们计算机的 BLE 适配器以及它们的基本信息。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111406103.png" alt="image-20230111140645973"></p><p>hciconfig hciX up 启用名为 hciX 的蓝牙设备</p><p>hciconfig hciX down 停用名为 hciX 的蓝牙设备</p><p>如果之后扫描和连接过程中出现什么问题,可以通过这两条命令来重启蓝牙设备尝试解决。</p><h2 id="hcitool"><a href="#hcitool" class="headerlink" title="hcitool"></a>hcitool</h2><p>hcitool 用于配置蓝牙连接,并向蓝牙设备发送一些特殊命令。</p><p>hcitool -i hciX 使用 hciX 接口,如果不指定,默认使用第一个可用接口。</p><p>hcitool scan 扫描处于发现模式的传统蓝牙设备。</p><p>hcitool lescan 扫描 BLE 设备。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111433751.png"></p><h3 id="Gattool"><a href="#Gattool" class="headerlink" title="Gattool"></a>Gattool</h3><p>gatttool -I 以交互模式启动 gatttool。</p><p>gatttool -t random -b [adr] -I 使用随机 LE 地址在交互模式下启动 gattool。连接到地址为 adr 的远程蓝牙设备。</p><p>primary 检查已连接 BLE 设备的可用服务。</p><p>characteristic 检查已连接 BLE 设备的可用属性,以便从中读取数据。</p><p>char-desc 特征描述符的发现。检查 n 个 handle。</p><p>char-read-hnd 使用 handle 读取属性 。</p><p>char-write-req 向 handle 写入值。</p><p>通过扫描获取的灯泡mac地址ff:22:09:30:00:18</p><p>使用<code>gatttool</code>连接</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111435279.png" alt="image-20230111143500095"></p><p>有时候连接成功了但是会报错,需要再连接下。</p><p>使用<code>primary</code>查看服务</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111436532.png" alt="image-20230111143606390"></p><p>使用<code>Characteristics</code>查看特征</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111437647.png" alt="image-20230111143704457"></p><p>在找到服务和特征后,需要知道读/写数据的 handle。这可以使用<code>char-desc</code>命令得到。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111437233.png" alt="image-20230111143742105"></p><p>在找到 handle 后,使用命令<code>char-read-hnd <handle></code>从 handle 中读取数据。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111439744.png" alt="image-20230111143910570"></p><p>也可以使用<code>char-read-uuid <uuid></code>来读取。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111440241.png" alt="image-20230111144016084"></p><p>从前面嗅探中可知,该灯是通过0x000e来写入数据。</p><p>可以命令<code>char-write-req <handle> <value></code> 向 handle 中写入值。</p><p>关机:</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202301111443278.png" alt="image-20230111144300103"></p><p>如果<code>char-write-req</code>报错,可以使用<code>char-write-cmd</code>替换。</p><p>不过注意cmd是没有返回内容的,只能从设备反应来查看是否执行成功。</p><hr><p>以上就是入门BLE协议的相关知识,关与协议的工具,有个比较强的大的框架mirage,不过相关文章很少,需要自行研究。</p><blockquote><p><a href="https://github.com/RCayre/mirage">https://github.com/RCayre/mirage</a></p></blockquote><p>之后也会尝试更多相关设备的研究。</p>]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>汉王c330人脸识别考勤机设备分析</title>
<link href="/article/de238ed6.html"/>
<url>/article/de238ed6.html</url>
<content type="html"><![CDATA[<div class="hbe hbe-container" id="hexo-blog-encrypt" data-wpm="Oh, this is an invalid password. Check and try again, please." data-whm="OOPS, these decrypted content may changed, but you can still have a look."> <script id="hbeData" type="hbeData" data-hmacdigest="04057139b6b7d909afd11f18f94ee0216df8574c7e937f2185b864ae8b19a83b">47d9635aef24c3f077639ffda1f136d76ac9af4d74792c3294b07af2fff77bae35145cdb77b72c924ec58fb00720a7c26c54e0d3e98e1b9143125b9d1c3848e39d2224fe4eb7ab046915a75d174f57eabb6db229a6b066c85cc7f67d654a9190ab823cb3243c5355d18ec7c3f4f8693d1698c58a7ae6099d20014aa44f25ae52c709bb10c8ec7c664477bb3b2e7dd4ffdc0777b2ee23cf49d357ecd6fed5aa604a17c32fd626b5220adccb61b6726ba0ccf92d70430b13a9f8516f58451d11fec92d41d367779e537be52587bd582072b315d9d62073294b25abb84d19e6940664559050d35c54604f5facf45928e3dd05f9b78d76151b7f6e0602a71d233da78e551ced070cd54990c3fd88998dfb61ef69045a83ee75ad3d948514318505a9a20c76ec7501a719654c59793c69cc37d60b745351a0c731ecd3bbf78cd2dedad378874c4117cdbee92ee2fb733e91c99d96134ccd3bc5402d661058b5a3b2226775c2b3f39cabeeca168b646bfb62fe0cb7a388e6dcf83de11a36d2ad88a5a4d9ccf9f9ee11c7b6d554688adaa38d707d2e527e1e3924a92c1c206b1aa136fdeb5848b192662ea49ec8d8a24ef7aae5c3f1f8c6a4299a92d51ba02e519027869376634e5dcc567f817f26f8ee426c7d18a2b786a8b1be69775bd35fce1f5eced734ae1fb00b7ea3e8e2ddc1d2348c9f23d4e0f3af2531056ecb12138d43f56ca41929c5905bc8391af83de991f32a76c39778324e4ad4d34d9c3e55601fe560e12e10469a7dbd361c1fd95093664113fe3950e46f699a57053a8b4c7dca502059f71428f584994d4353e2d7bbd7323da58860fc247fab1d30dde14ece83d29bffc2bef6b661572396339ffc801191923fee91cd7b1f2ef8318f5a40e23ce2402f2a3bb338643796ea812eaaf65b56c0ac9d7e3d8c67b00f78677cb378382f544262e88b833188cfb3032926e807715fdc18d968437f6032a62fc20aa236cab3334fefc7e7ff25a0dfddd84c691c12207a8620317f5775a0baf44a46e2f4aa0fdf4cfb65e446acf84cdb0178e2ab507b932c3457cef5272f2c2da17cd86d5b53613eb6234457564d71d24587c1425e6c39f9eb5ba08676124a9a1e2195eb0fe5ab1d1499762a802f27ff75c825d765189483c4cb35550ff3440846a2aae5c1258c5707c25444551fda50d5545591adb6cb2c806676561c6d4facbe776329962f5581fba59c8ac4a07ef9026464b391d7c3c03cae2bfec72a352cf6532bd6c50b75a821bb5d33c2c564c207d1a90d02747d674fe52ae3f038754ffdc0ade85887b8778af13748ebb990d9458996e7f82921ae2238ca03cfc26d1c324adb244a12f12bf83823b1b3f07771ba3398e80489e2f35fda98b22eb8d36a545448b61d4a4a9ac92e7a377b54d43e9991a383ed293d5172e1d043c650fbabfa642268e519319cc9b29aced576634ff0af1648ef9f531fa4ca18fb6ed2292739b7e2625983c82a482d02b3e5b34870f9b86e041a5633a6c6f33e6068e4c797be52520299a8bc900127cde23fd77f7064aa5b6502ec66563232e0cd017179802511ec956de57168053e0d16ae69302ae8608a5a298b50c4d94113999cc1f0675b27ca393a1a937f231d329108958ccf93662d8e8fc8da6dc4589ce4283920aa7b4e053d3044222cbc144894dfaba20e5caedb9e72b0f4b96eb6b864013a09aa92b83f45dab7596e04da3514c0c9fc22125a5d8ff8147d460816b39c942a0691deb7360946af484499c537cd3da04c25326291af3714ad31d06a5f29b847d247f37e6400b999eafc0b37a083e2983f802dc99602237c9bfbaf0e23bba491c3b1faa7ec13ac284a29fe293a273f3e1d5366db9da477160a559b6c27be5a8d8772cdbf9c4086831a5a1b9028b1c93360df3a846f065f9a96406c10941ceead8bb50baaf2b25ad7254111e97b360a469b63f1072de2fc54e96763e7830f8b5f750720f00a972f228037282b8cdfece352ab2f19fd84b52caca99dca106113014b4a6a87faee87aa76ff0d37f356beff74e5a5f5e3008d254c523cc680fa2bb643f2e1fbd67057ebe61ad407656b986e1d9a4de1dd5770d810a6d90eed71616514580e1cf69460a5f3218f25db993d9f53dc43a81d2582d011963d2682135fc451eef48a793a11830daffaf99ae8d660d5a0ab07f869c9be255679e9a206d3b5bd1d37ff6245d278deab6acfdc3c8408d2ef8ff48a3d07a69fd7c52aeb78571532e41acfac0084f1b189656edafca734da89277fe06c4cfc40ac08d3568a0f6a88dee415348f0169fa1405d470abe81c0d694df418772ce4605b931636fe7132a9b46d74d5ec6605210deaa7e9a2323bcb1b7c588cd2cd873ad74dd337ff1b8cf684776363783491a6b9b38c69178aa835f1096e734dc1e5fb755d041c795e048917b9805b901c66dbd644cefbe6e6b0924b1cb7264b5b17ac5aa74c5464c3d30b4c59495eca158146b291ba89e0ec6bacb31eef91f57a8fc99b290e151dbf743011fdd0ba2cedac36461469b184f0a39bb9328a40d488d46aeb9b09fd1d165f2fdaba46a11c7c3d34cda7b2fa6eeb5b8a3e38c09c0e60831a2ecb51645c5196161eeaf2e6d0540a2aa2618c9502d77f3da538d8211457fa0cd979716ec588f516a22aa6c7ac52c010c3f1c79ffd822367c49c630e326dfb6f4182ca44cdc3ef59a5e2d7809ecca68011d71645a0774bf5b69ed69591321c8c6b87c7ca2b2ba61916174beafb5f324e5d0ac014125a0da7f64484b922196b3109eaec87ee2fbd5e4c764ffad50b69affeb5131a35f1c81cf33082426d378aa1a01c241436523c20abb0f11a53756f1a76d01394d41de6e237c3ca8f14598f73beb37238563a3c03b0c636899045282790f821ac3fc576e7d78f4de836eecac1a20c2ffe8cf620f880392a7257c0d97b8e006a385d1e15ea6fb6c4b43c5fc118dd07f1624b0a692dc6d36a643b48d7d180b7934c1bbbcd98238e35a562185afbb2233fdd64bf11f17f7bd424d45ec6c55e8f4533902e64f5d8f4a75253d100e3a2125a28e246311f2816c3b4941b40febf13f705a437d1da9fdc6822b6936bd5a14e8545185debf9ab9095fefe9a76b7592a83798f29974292aa7004d981106b8b627fe67ac2f21f0e012a1811b2999b9e613cfdbe21e62e96e51ca715ca5d04f059c27d3c7753ee0dc3c483ee1d109c28cef64941c1005e541942b3dfd176f5d25fa9b267169fc7477c39898c5d909dc991231f919b772090c936f6c6bd9485a36a810ee5802c6716efbf22fbc4919e6b2b3a2afec93bcb4c5b7adededf139ff8b4d9c7d9cd8cf456f2dd204c4cc10698e038f6db14dd1984287b9fda96ae450afa19e7192292e670991c5b6766c645160e9002b4589795dd7e7dbb30badaef0beb7caa852ad720b4f1be2507ede6bb5e6098dff8fda8fc786e726bfcc74f6da96ab159405519d337e98614d38ab798b944b2db4961d066c89f3fc7a7b3ea4ba72941206a39969d09208d2c8e721a5d0690c738db8b7aa57807fc79aa77d24661809896e4be6be1357f95928297aeb5ce417753092a9869cff7c5ff135ceede01742848d2e7c45cf4382d728e01d8fb8d48cc567aee41a36c10e2451406a6a7ce6e5f9395593204c3a33d0d37d579e001096d8c81267247528ebe1b25873ea4519be7b32525722e424c4bf091caa5008a0fef1a0c4c9a28fdd4dbaa64975b84a4d26e935f3e5122dbd68f50989fe384aac3bb37ae9bdee3bf60c4745ec8565f95b73764a90c07fb286ba8908ff5e347412355cfba008f3857d82423a5249d765376ae5e5eb8c64a0f2fbcd5dbb4078e9dc40ee960fc5f5d55d08207832d8fb7bbb09af195957576e439846af17d3f6ece581f90b186ceb0fcb8a1dff1c254d4ea3b0b57847d8615ce1e32fa05a00bed16dff71b831d5b3e94db23555cd5dba804263d6eef59bd75d8d3dbf03f5a1c1c50445cf5cb202f4fea9553edcee6108ac97b358f932977480587bbc19b70c0dfcf404a3f576b32f2985ee165372049cfbcf8dabe8b9cd809991a977ca6794bb535b29c49cbd229ef086a1f781e92cbfaebade8e835056e69be66625eea3d9c67be71cd1023803c61122b65e7380fdfea44dfac913dd0896f6bb1c185f5ad3019e8773a231252dfdb09ad1af0ecadbdec0658d7c02f57024a500d5c8e55609a801f1853ce26d47608f923cff08d8c73e0e81ddaef07843c8d8c5217c74a6d33b7224de35932af7e3a8292fa763976f95a88fa41c91619327873eb38615b6dd966d0892169acb41f410f973f190e4188f75c18178beab18612a887475521251b54dbdf8ddcccabb076f1d461aa0fd7007546dfb8544a0383d8f40b2777673b64c001c1358a30212e2772a850fd07e69e38ce3779bb64db8f20707820826a484845e3bd27c70413204f366dc1bcfa5f4cdb48ed09003e5be77cbd004bc4ad6023ce34eece4c6da3c0e0535b2f5be05624efd7e63901f91d2e99cc2469e85558797590d7cf0cdbe546f41af3e6399db224c732e032c04eb7dc15ae73e9db9f96286a1a55fa79e07508a5a83c48eac41cc1a4b1c7fbb0349c45f8387a7e9cdbdba358604b1fbbfe7c3fe4c76d33fb446cf566a002e36fc8476a1bb7b9fc7f9877ce0f1b57ed04d221e3c6fb157a176a2faff5f0550ac43fb1138498814fdd61621e9022b277d7495b416feb7996fcf003abb7e084eb0df529a302c388dcee2c2ba5da1149ef4a6328762bd5ba3db1b9c8b390a02e01611a33105551b097e4e5a5d913e145d535562de09e749321974a6d3507f13323a7d81f8a733909575f318736208f10a1e75b1ac18f0065d3d931b49f43d160092d704e609345e1e06ef199b3a9c4818f927a193c83a71cc146b7871c398e2fe1360b20b6bf3d3c343381bbb4487c4898ca6386ad2281c806345cfb17bf363f4087fa7c56452f094c29d19ce2ecd15fad3880b515d26ed0fa051b2a787df2d6ef438510bf7656cbda96497b6d7ee46b32210eaf89c5bda96669ffc4621a451f972ba5208ef02bffaf7cc7769310ba2c5b018cd8e9be5c8634e367fe5b62ed3c922d4dc2db4d97e9b0413cc1d77ef82deefe462cabfe854659ac266ed366b3562307f2bd2ac4423decfbe8f3564f59bf9134836e77ce776d5a00e8eddc96c77d9bc1f8f44c1e6d7adc9a75d3350040c3eee49a05caec0778556444122c7e4c4c14d52e5544b726dfd7db15d5e03551011bfdd4d8440271fcc4958040723565390ee25ca3a52567a2eed67e02cbb84621670486a3ab1b72769dbf982d9b6d537d0bd8fc202d8f381c54d0776dd18f5e52bf7a7cf79daf3b9e6f93c6168b10fbb7da8a80d1bb4065eb863aef632e87d2d6970e048a50c8a5dcd3beedc26e57db3504b84b94c7ab8df3c8c7973c58abe9b4e4ddde8055ab98ca660d219fb4809da9d40599030782edc3c88b0a0e4072b327cd2b7bc5b848f02c89eee29a6b05386def28018b87788c209c0bbb429af6d02a40f3d95a699e13e87384ce838edb2fa3a797c77baf4ac1b33bea306e752df21d43f02281efd2ae5a76f9269ea27918a98c16130144b714bb5088319683b1277d3ce2c7155ce8ee2ca0e1c93e55ac390891f91538b5c7f533f0f773e48a50887e3fe77e35c142b9c7873f0577b0ec0e15c8b6eea001773c3d098d4d34047d4c7b4faa8a09a74861497e1b55e2fc83fa3a267185f9b990d306983682dfdccb718eb7da48c36a8a84524a1aad9f612b5937741f383fc9a24509a6d5976fca5eb340303b89d8bfe224d72cab24477138d8f0a3ec242d6f8eb5a7de284ed5fa4a30dbaddcf4bcd1fc2a69c4d29f0c9112332bc9b014b08e30fea9b8775812142557f1892cbbd120a00416208b2ae56aa8e6466c21cb4bf7d1505eb8987d867590824f739a59ec198883ced5ce0390047496e4a745a7697a5214e0cfde47398a46e210f35811b3c555a307edc8af5b46bb83abc259e6c74df6ce5adb433207fd41bb450fd32500effaa6ac0e51de6e0ac56d06f4013e7058d1ed74d486397cddceac15c42a72bd0b9b71537aaea0a69eab6a8c4ce7e5104bfeb904affac9b9461a36fc11ca91fe78d70de8ca9e0d0172a92b4e5ea9333c6353da170e54bc75c7a338cad38fe1ff06079e31c2d38494932da04c629d3ce3be53eb1db402f026bd1d255623e14d203c705586f7328174ab8b57ce8e4d39ec2cc4b9b957b0fe427cd56974f10f1047b78bf79aad66463ebf6197dc7a821caa4b564d31fa6ed8ad7e8bb5522a9e4cafba1b5571e21464a2698ce291ec140588e2b519e7f33435bfe00231675e6cd80b77396edd176c33ad56dab8d89ee1f65c6a6606efea3727eaaf0bf09a4bca48134f2918824b3b8b3bda260b5a17d9a51610fcaf86f40effebaf733c34033dba6c32e1508b4178643d6ca362ee7320105f14f225244fc18edd17fc99b9422bc8cb257e6d10b6bfc2a4bc24c9f0457b70517bce15d7f023aa18c1cb65d913c006ab8ea1d65a9f56d3ce3ce309c4bc65bde6abc9da570303ae348372c2f402c7e39157a9fa1e297d452e67bb00cc161fd26d19529870aafc830d11403a37ad100b6ddb35fc20b5ef86013280d0565baf1a4c7876736aaf4e8017e8dbf82f1631e06824e283195aa7cc6c9dea9f23ae6c2d38ba7a1dcc49ccd791dbcc918dabc0beec26a6ba98f0982c8dd3a9cfa1b82307edd75d8ae363b3cfa7163e63f80e2f8346246def40a201b3f70a9b44efa33bb4b79eaf3c3bb97b5f5e2918d507590c022daa79fb9221533094a234a8fb77cc71145f6796b8a23f76212c53886ce8e4d3e89e96063746e06791a8655017317f37f7a9e397382509d5fe8fa820cb76ee7078ccc39c2eeff49a86b138d884bd9d67997a32846764b6a9435e87f76c84566f496b59f6ff0446c06ec378a1c9cb6c137154a0efe9f4144d3cbfd9fea51e7d2fc16bf50cb9ff3e84ccc40f9266b6b6e48212d5e90a094c51ceeb8d02e2638e1a9003272561305e36fc1607b9682ef30325833fc407567fe237bcc0743abea2b440c9f21d5959eea57a856b99e22394daef61a8756b7ffb3b56ebfaa5bf0c5268b59b201a34d82380721f7b6966b9c52e14f46c813d1f2d6d37f343d0c316bf9d0f090545e227a0d3b2d710d09eee53d2263d1116504ddbc9ca543e48cf362e99f82c48071f9a40abbfd5384c6ab0fd46d82759640e63aeebfaafe65fc5cb174c7da9bcf44524840cc021bcd546705e23165bc9e7a6ada244ac6e33e5756cf4788f1e0572b78992684879fa490c5a2f246347907895fb67db3c3ffa40681bdc86e633ea85e2012466420cfd42aa045cad85bd1532e09cc439db77ecc3bb8683eb89002642bfc4ad2f70ad34e141fe4726b4be27c275650cc7f6c0f3a01d6f471a150d7757a8eca81caef39b73c31acb0b637f744f4ee549d1403891d0193401eabc2df6179d0aff62fb8b4867c498e59725f6582a9311482bedb17cc698125943ce3fd45319970174b06a9fa0256129197cdec789455a66c027d59794d7d91f413817249af6e7bdbef0875d81f19508ed6a4198639b9c17c86bdc4e935f7ce10cf41f2465b2d3f764e28d76478687d1ba5fa175f9202db994e36c6dd76c30277bc2565f64ddcadfb0598a233597c43442c38d0103313eaaeef21740cc0228c742ec23b6674367775ad497a017f2d3537e3610ef5c4bb38aa60b5258d75e779cdd60c522fa1a7d019047ecc95e6fd4e299fe7dceae89283b4f28c4049c226a69926fdd915b383d16abec95364d31516209ac9be8785ae3821552415f77278fbfe7495af0ebc107de82b900e37d5d3acee1896f4f6a726ce28aff537671016dc6ba1604f0fcf563fd4019db927e385f2d1f3b3b861409279608890fa28bbf2e7fb3357b3efcaa67acbe6ae561a9fae1ad9bc9e105a8f07fe436b132ccd42bdce5e5fbf5bedb2a3ca947cad46135ed6eabbc2db1c4ab4016227e2ba082a035e03bf1d91898915cd9e0aa6e316c1c4432a7c912b70daab35dd601df2b01e88879534ad264a37b86150a60a213cb7c7e91c29d8e01eb9eefb94f66502a9cbe741553d1cc2848d86c5e1007256be6475a0dfb7a70024c2de27d5783b88765662fd81a6a24118df34e8203a427d627fe7c683f22b1b210e7fda1b9cea4eecfd23451c60744d8034538133ff3175a55a3bd4a5d80ac7a61f1aa914d8e33e2f1fe2b0e729eea3423b42c4fcf0b033699d4a201564b318fb35245ac33424cb94de28548b391f918cb97f730db32a9f196f3a1c79e1613f4b76643c5f554bb094e7fe3db6af200fed9aedb8f1cbf3767893028c096bab97d2bb0c7eb635cfb9b51652a27c90c902c8b764b092e4abbfaa298eb6887c2710e19d059ff2ee5921056e777f0ab5ecaede160138710b8088ae29a53acb165b56cd3123516a4006791a081afdd96486ee731f4ffe726830d5f60000b55957802af0d4732ad57b3a3bbf42f33a1f8deaf83deb5a44ebde040f2dbefced9258c72cb4b57d3c7bffa04859366a0ecaef7725f325167efaee2153e831e704a08686fd23c77ec74fb9ccd17759240c9cdb6fd3a84dbbb06efd9e97c969181c9fda605b6e0cf576db55125876f6bb22c0375c9c13bfc8b14ac67a6c9aa28c240c75911c762405d5b766f45e8a5f605b184789e158dcdd8255895d7af72018b5d7ff2a17d4b5eaca243df89ddeea3dbde301128079d8fa77803d5724fb8508260c5d07a68606fec832dde0c0ab7ab34b532d86ec4726ab8c75456604cd5439b8881fea6ff658478a4a2842696a1ed5dc8784aa972f807f6b23c3fa84795cd50730e16e60ed8010fdd8062e448f05ef0f97c9952b2951cf8b354904ce9888f5050155b4a60de549534d87d1126fd314a18ec27e0b96d2c9a1eddc8c62a6c2837c08c33ed73d61e342395b8890fe770fbc4840c5e9282d7e10f8073f5b516c38a7a927a3067c7c7050ab18f51289896e7122f5cee1c04527f0be10fdb803bb815003947bcdaf25d11b359df989a0986937716be4449d2935d20f63c2b2b1fbf234943e278a4ff8509ba945c6d2a41c3dcd23c64580935a0cd8faefc22247afc9b4214c41e0a220248648fab340aa05dfff3b76b23d24aba3a74643004dc89f46449c2a59b57985c66b6824cc9e45f7af211a8b3708d4e79c8f4d6793ef5958e02e5a07443ed486637a249bd285805b8c642bdb8de911ce7d1aa5a5383bd175ca614e48fbcda5bd6e2311b3c123cefef5ac8ac25b1f2d51aacb50725fdf525161a0af451f93a0f2106030b96387c6fce23bd5fd9070a4c6b0431066f092c6790d40818cb96d234a1c466a5a7c25a05a35fdc1feffa7297b532b88fe357fe38ec0c52c3683cd13def12d1bcb9b01dbc34a872df872743c0fa9a53aa2b11a1d8a092b4010d8d394cceca56e46ba7eb5a537c48d4e86e96ce320f4f53eb443868278aeed14ef93ff557fcd14a162cf433813931fe0e7f0e6ae4264942e73fe7488634b7d15604d30a93dcf625caa25c8345ed887319d58379016ae710d1b4ac9e2b02f2b1f3e0e04cc091ae9d3a17561c68b81f65eb929ab9c35161c6a9d2870c609552ee0e63c546eceb988f8b58966aa26bbb308ae8c2019ccf60e538427dce18a2bd53f547501fbd77bee7b9c6bd7b59c16823b35c860f49325e21a355eb05fd3d5d79d37596cc2af93a306de363e42e431740229b4ab4553a4655383b37460cd20d1a3e86d1a222e16f52388ef862d488327fcc1bbe47f251fd6207cca3085fcddf27ee308c41563fbda960c414d8cbdaf66d32c628746c3fe2e72468ead9367a1396c5fa38e437c98fcf5a6c391f3b77408ab1c27a927d8717ad11aa9ea34bd14b68ce4c5d99792636539f619e3c29530a2d634bda364eaad9fbe4385a97e6cef47de188edc86f0c3d1c08d65013044cba256f7ff9b51527872c57839c76d157b39c3b191ade982d67b0237ac2f6531092af1fd71b40af5c3e0b651e29425f01d0ee9987c18bd4411f97a2bedcc49470e08c341ee6098ece27d87f7631a88169d423a2b9081c37d6f1e3e8a87250fdb252b2b7fb375534792425405a991293905e112b59843b33b1b119996eec96f24f4788cc582c5f2195e454f275a1268e817a21f122d38cf17c6512455bbae3c25b300d4a78a2894b11aea9760d22502d5939211fd9bf314f81aeee4a68d4caa72c54248be3002ca5750751308c7f104ff5f956d3e2c4f1d1eb79e14fff73af834aa7a7d8e3a8f83141b68ec2d300b1ea04dcd69034001c4d1f56bac54b452f8ab974a83054167d089581358bb92a94f50430e8a7937edeb1e5ca2067e9d9a153ee90f7b732655a773e225b5ec23e68ee8774417e056f27bcd744e198a00e6c19dcc1f340cca04d6d9e55cc7910b9773c9da40c60af2e0aeb078b4898f37304b8dd823a2e76ac3aa1e62fa8465a50c1042d5f0f548c45b5e785d243620eb8614a8f1116e224149aa0be72e0ba3551137c0b89f3f781d1f556f9face527dcac7eaab7945fc66bd0fe46642e6412c89c25e358a09ded54c6fdf579cf99eebad15e26b9aa094c4e44b008373e391ecca91b6f166b23ebb0b27be46f464fba9e72521b52255d52a2e19589c1cab715e9dee2ab734865097ec6d705fe3c13ce8944b8c57fda9cfeb2b9308ea74976227f42f677071748c6dccff7628e0a75d0937514a8f976bc716fc836123132eaf156b027c492abd5b6168515fa965618f902ad9bd7fc50eca3d1e6469177617c62bf26e7a03132881577d57f2f177ac3f02253716f533096af59c180936177e26704262c05e0537047b5344707b3fb5f3eeeb0d37d8a75e1498ee49e9ea0a569e18752425993c3fcb67db336e2b3147131202cd146c93e48912e787a6c4567f81dc680418a93d9b0fb5abfda914310b8cf6a422ada645d4b1bb8a1fe98bb83dfb26397545777f385e9a903989946bfe11e1025dff753e617374af4f9f69cebc753f791b6c3b4caa5a727c0354dc6b347de012381977bfaa37a36eadb94a31b1aff2f7bc698dde0e8744aac1a1b5f3e285b6c2ce6c5c899334f5b069b2a3f0c7ce863be82b6cc8e1a562677631bbbb1b2eea2d1d497458787fca046e70675de5911de0fdd61f9ee5a397e27f5ddce820e27b0f2d2abb3adc5667e204bc02a8272fdeaf89f1dc88f77cb8afa7799b6f287e8d23f1e699a116a1152d0adddbe466e63e33d7f7ce480af3920e1a2907df5bebb327d3ad027a119b1e1f39b4f2e36a01fac257a5773cf1582fbc82fa9867d3db61ae19f6eb02a24e2bd99f8fdf8713637a0f2bc83368d5ce97786502425b022eb9db022c1ceac7a287ccf614d07a8f402fe73fbdc893be563248f15d0aa39bbcb1a0ee6226161de8dd9c447fe700368b558747c444d63593a4ef97515032b953cfdaf9c8aac54f122fe2a5fe8999e1ee95bfe65de3d9cdccf306e17005f7442703d8f7223f2fd901a841e39c73a614288fa23578fd4b846114742ec4b8540e441d46c0dda8b470f1755ac44ee3322e4bc9e4505454c617fc403cde3f34e7b5bf8077cb8c7dca4f6fa2413034dc02b2177a077d625df0bd7040f3a065d3ab658c85713ff576527cd4e833d64bf3eb135dbc292794a05998387964068a75d53b166e9ecf25df2eb737a7d44c3e07ea4095fc09e9b047023cc6b892b3f8bfab062bc965d8c0c17b6f78bb0ebbec5a8e1c1ee9691a28dfca6681ac5799e403ecc213b5a307961ba9395e6a89105cc01a9623fb75af3f2f4ecd9ea9704ffdb1057bc9dc5b4c350f0ccce71f226b28790d1dd389eccd8497cb255745aef089a334b84e0bf19760a79081d5cea5dec3c97e59f903d176834d96cd6500e58bcfd3d874dc87d166fbbea7819f47d2499cb6a23875688a026cbf2dbf619d526bfc8c930b0665ff2539347f2a028ea805aa4fe41ee01f061386099e666b568b89fd60eba65b1fccb9624f4a3bf90b41129db6b7f0388a579cc709a47f24d33a3ee28e68c14b56e7e8f153521df4f52c61d702adf4a9b06c27ac75fa4aba926cb10fe54b1442f0ce32956ee377d54e0f4d96d552189948b2a4a8a0d41722626a5e9996bde4d6493df3e589e838690387ec90089172e0c01441a471c9889be5a8a46585c70116d32ce6dcb84f8987de20d1082983d55f14463d29f31bde8e447e96a2efeae48954724c8e96a6dfb0e949df4d2a518f1440e1be59c0fa1628b496ea934754b6dc44863a247554f0eb1ac0368f62436a87548348db838a1b6e0c79917aec9d66b5ad554661066c9e2eef590aebc23dca8d3b3578d70681d82e5a71bdb6d62a611818663349ddfdebc765884f3f112eea1d71c2ae5281cf90ac557f2d55a2dde392cb418c7b32446062fea3f16f2bb038c86a3c0caedeef065f169d17cb672801c183e2de97c320dacbdb56341ccd033e144b377a8959bc02fb4450497fcfd56d853baf415d1992b8bba809b2f1c7f84ed836be15a3592f031acdf46f630ca5422eb2fb956ddcd8b149b416a2575edc729abb9125f6d7b9d52f40c35205edd803d5ef2b7dcd439967e725618a6fafed4686be3ab596e5a2c2f06c617961fea60c21a0e02f372143215fef6b27256ec34c2b85d405f3de3e0c3ec2bb2ab0af147e7bf33838c9cb79286468b2f7108d8fc4b83c5a68242c71fbf390175a9840003e01eda12aeb724cadbc6816cc24273d5a37f75d8f40ea4b75b2dd1456c593a57fb2a819c799e240c000b2c430564123e84ff0b76e791b15d7ecaa25b5fbdbff8b9842ad5c3cf9e8f6441f86f7b930c2c427f0cfd7f10fdca0b5e251878adf2bd04346538f8c4593d27b28a8acd92a15f6a741273d767da7897f45b4fee67bc3d2bca73d02ba69b3c8f1ef1365e437273d39ba428e3da3d0ce8ebfb944b4d1e7f49c6fbe93b9cd94c26e8f668a9125a8668df55ba4cc0ea3e3cb6618c11c8fa868d0e4c0e6458527251dbf6529bd165ad514aacd81243d260374a9b001320f7bc2df1515c283faa69a33048ae1b103e47566c66bb3951ec20773ee57978fd258d45c8bd48488fe76743b0d81c6470a48a67075aa39b61673f6e0737274b3288189ccdac0edb401328c7b63bc9084f75d08145b1d5ebb47607eef6c7e5d9323c58c3c5de8df6b082b308c236495436a4789f51fc00254b54a0c3d068a7474f4269b4e136b86774b0c940777d5a38a4e2fd734bbcfd3d7ef1df1799e2d54e1f2a32a451b331aa18929957576aa27c241160cb96eef89ebbf4995302e6c0cd71b7ae90144d08cd97d02e2957dbb83122f0f34e31fba8b1e9c16eaedb1e49c328e1816476e31e10dd857af43c54b196af9b9e8782190a41dcfac56e488090bcc111e5ce8a6f35cb00c59f3702c8566f095e089f469761ca6dafe5b1e444f5d5f3a86771a4df98948a089701b965c1b812f46d8f92732e634729ca8bc94a16a9a98dce399f7395fad534c21f6883726d80eb281fedf4da30bac3888e5ab0c740fc7a2e8f869e1bbc9bfa756166277cc7ef4e44602bc734afe0d6866ae9da3b09ee141374aebcd52efbb115c425b16ae56b6b55c3e147bc7b511fe8f1e9e4097f15ffc66dbd8c584c0b8bfab1b7182878c4f542201f6723afe254ae323ce0aec53729d3ad54d5f5b210a13f8caaf2a2b2fba4d7ee3360ba5d4c2d4b344f9c22671a4b359adac602ec4f1084e1801c2600acd5aab7c2de78aa549eba9409e3183a84e43c4f7d78cf4bb5b4c298672715d157a3730bbff858aec723d5cb77a9f80c0063ec4d622947b093b2f6759e97585157dca1cc7578e5d7f4a906372d95e68387416fc783a31819d8b3788dbc187238e4e38b622b1294e32b84e79c4a9dc9bda8cebed7c112ea6f200ef9b02c72bd03bdd33e232d70df7276dc4e9f9efdc12ceecb63b074bf41064aa51cb56a673de772ccc60e2e113e08138c313a2e26f4ba103c8dea05d63669aa3183e351859e3ef5724cb9226e1762c481e9b81eb8ad63c04c782cd1c52ae0d73f3d34aee9b5953ef741aad65af281c8823c3ea00a97b32215f11086de4ae255d1c3772990a20e56473c2baecf1d2564de965838666aa61c44af43a4efd7d3ab553b14ed6d74652eca2b726babae9b97c193a880779309d38c1f6596e4827965b99b00d0f7ac1690aaaca19c3207726dd5916f8d35185e6e360f4328d22dbf46ccd681ddec03c3e390d562e6a4bfa4e63a4741b4d7e2600fe09c24ccba5d23a32299b0ce18dbd27554f88e0df602c4905b4da3b8abceb28e267b751f5b96283e95798acf1d7994da3e58bd554642d8637aea4f8f88a6d9db5c0c5e621e1a753d2d2d1c6c52f2add8677de7b9a2c84ea83414f8211ee9f6698955cbf26ccf17440964e4084040002e2b5007da4f2d5339726c8207e23083a7119b67c3b20573b898a53e26b922b901df107a35ff568c38dd8826e3ba3ad0d9da5091182cedd9abc78e31a8f51afd002e5cc4c9533e7ed501987a0b82f4cfd2201c2e098e022275989386ae53077cc52bc37d1caa29f04d1a056a1dd46b3930cea2964cab776c21aa91b981eaf8a1a6114edb4e4a2f5c9c256ea95dae6c751d18e036ff79fbee8278c06038171f1f022a3a15e6643b4afcb18f4926d183ad1c641f3197eaaff90f0e734938c30e3c276e5b2efd28986a3ae64de5ae1b1434da56ccd3de74c65c1d1863a4d80ff8ec815fade4ee48dddfc64b87a56baad9f47a9b211bec14fa89508466210f935a9f00dc70b8f465eeb111c8232191b37310b7381e232990f97ff50f96030ebe53a253dd15e616a55ff9711decff9a125edfda3daa23db38a5c2415c617211523fd8184e72345bd7a8cfab5cf7f683421823e10f9e7c505c8aea5c62914d707035ec45857d81dd56ee6d10f11d55e3cb7de1e7680726ac7c8cfc8fb070b727e163042dcde967a124c0fc1794398fb1e29c625cf8c2cbb9596e0a39dd0a212d2d05a7bf0baba52f9c33708a17f388d0321842b958a8320190ec80ff9dbe15577ac36db0b7d289d002b4f1593b426bdaaff33f2205623da80554dab0096cd377bd0bd0a5a5568915e1d79289f04b06dd9a99d983d4134e2010e73049cabfb977f5499f72501d2ca78c0c273a4cd306b9919d1e3d0da45c31090baae4df6fba514036179c2d4c83b437774bf49a3d3bf9e6890b8214beb19a3ebef07a96748960be897dc16545d899f2660c31800e24122edccc8852ce3a0c1b4ee20884249e8184dba1f02759937f9450b641b61f20e3d28bb4bcb746592eb718fc64604f4c2abfb34bd9afe8d36de95e238f4605acfdb3526157472282078bb04375ebf1d5ad425210990b1957e2e7fda5afee8e9380091c8a85c78049ea9fffb90ae648b470e645eadea5be329658ab2445d5adc4b9f9159fb8422629b1add0127dd54126f35bfd4d31717fdce763d6468581b22fa9264c1753d6d7fddf09991b1ec4641e49abdc5a985ed3ebdce5218216a7605a3568e4a8314b85c32fdc89fae632a963cfb927d095151cab8b8ae1e09d1e6ac0e1d6a418407bb09b826d8f2458f5927f5d06cfb91b18ef687d6a20ba004128ec5c585573425141657bd11946a2aa52b209dff450128bed6a4cb954dc836099b5838f7c2cf413e0bff1fedcbdb8eec65b1bf0808866fad92acf509527aa8004e549c89cbfdfe7fb5246df8d586b87619f2497cd24c4f04542f36a0cc55a90240373554eeb6d48d5ba5fd83913233ccebf2d757f52d8bec1969ea55f7883ebea9ff000e0415a9d7e7537137634494ea0ab89aa525438481d73289ce4bbaf89520ab754d53de0116af3dcaef5a4444b1b2b51bbcbe1ac62fce69757171a293e87b529d89587ace8c51b19fc4cf223394bab4f290bb12263877fbdd02fe65125c991f4e12a344cfdba8e3f220d095fc34a34010078f170cee611a8148c9e8cd81cad26a5a52a1721d9df8cc096bef6eb1bdaa2fbde5b486dd97efdac8de4ef8de6fbc6c4852020ff2dd9efb654fd6619b9566797253b46ce025c857fcd123dc657bd1cc48d36ddc30be0a9a1a29cbdc4f9731cd4590c4074e3b507700ac72397377c4519efbe78b1ca650e488d216ceefea55d2bc9bff777ca703101636a09cd577d170cb353edce20ec41fe7bc8c24ab2dcb5a1dd5b1ae060260ff55dd357eab37f1f95413ce9261fbe0435b94ac7e982d5186e0424b9f18dc5dcbce489bc41cf3136a0d39425b0aca1c59cdd8f9de26032542c5f25acf809057dc54b821abfca407951fdea27ae66343f62b568f73c20790a2ffd605bbb12a128e50157b05aba0b63f79e04ea5bd43380e5e3b287663f1c814980b6fec48e60fe97da9de8818fa01b3a6d8ee2c2cb4149b0490e1c6559dd4767bd895b263693fa5eb671ee0068ce18d5434a2becb3ca0838a81d44cf02cd50cdc1800995f31a3673287860c4119091309b6ef2a2fc8dcdb05394b96dc562f9491384383fad5a624430e5a10af8a675ef631d874bd6fdff59ccbac8227c793536487be43776a9d2c414884754bbb47ee87ed3057a0ebd439a9b518ab1fcb3337c129a22c8b336a53aec2357b7c88e5f9a69a633d0efde3158ecd5aff7045dd138ac8e8cc8edcfde514ec36cc17978b4d492a9e09a7f921ed3e194f6771934d9612ddd42ef603b2f4c280f6d2cca0377de9291ca3a3e7cd10ead61f0f434fe2a1f300d856bc3e4159cea066799c7610422aad0d2ae49428e8dedacc8da76545daa62dfa63eb933fd67f36f4fd4b644ecf3631f80d40eda7b765e8d75d1817c1074e490760097424ad7f2155ebbc444fad5acf7ec8982da497703bed0f055316bc8df24854c38e2371adba541fb7907b5fb1e4e258df3876bca0315b7bfb5e501efe02968e4ef90eda97a16e6f89cfdc9ce20a4e39e4534e7a3adf48a726a7eec51bd3b16122898948bf1347493dd457e4177593356bf75258de3ec6459f67692da3e7c8bf37c40cd6ddf506319bdd53048cf6000e8895b1ff2582544630e48904f994cf8dbe369eb86983d78168de9852bb8e793e5a0d48843fccad30c17eccbbe476d74843c9dba9cbec48fd8ac0963d2e893b78fe5e87a9816f6ca01c71ee2e9a799bb3bc281d9a0781f30e8bc538c66a1510671b36f473a5c52815b71c0a457dc432a03c85686c4c2adb591b71d0f1607a759b24acb2c68afdefbb10cc89611d17cf3d9807ff9659a5eb80b64de7d54bc09a18b21be29bcfa489693d0ce20a6528defa3b81f4b3550e84520f8775892fd90bae7781bd6f8d819c3d75db4b50550e1f7615e82dc987150fd367578450c34b2c196857de27018aac4d0cfccb58e3b6423caa5d16b8c9eb87d363935bfcd2b273429c3945b20b810985ee8e683cad48302fd1301e108ac22f3f7f7663b3c84e692ed47404e52e657c6974c3e84e2117102c247638fc96aec2268dbd59acf01ed9b7d77cba7b17a06abf4a53cf8ea0d7d6abdbd2c4ea6d6c2675a9a49c910212361a54c92c14d021ad32591ae065108d789c6fd2fec404c0f1fc4b3f5c0514d14d7584476d3d4804b860743823fe5a80869a9975326f6a1d2a6e295184ca46303b3fbec0cef5096e43bcf609fcc5dcde245bab6221fafe6f88419da6cb2173f37d8aacf324834f20623d4a48913a58ce824d5a2742c10ff9f55cb79f97231bf7f4a08613378efd2b9697be988eebd5d7323ce7a2bec0d01a21938253384bf9e00f2db87e47a0fdf4a7f61b45fc1890110743e2503e44dabf077560e9d9e16a3e5d4f5e67319b28ae4c5d6e5f834a81f138fca3b94e8da5b8eb2df96766c5351a0d89de3411abd9ac92b4be3dde4e85300f39b95db291d7af083a3de7b0f79e4506c9d8a1019040318970b5fc9739ab48e4ef51cdd3040e7186b07b030440f1c869551f3bf0f92feee350ea3a0303173459f9a78e36c33806937ae54d60c9aa237521438ee5eb8324144265185c8f9f0db3e5d089c6185b73661c76356059ffc7d7b07266c5a77a85ed3d9cdf9bed08989d89edc1475e2d580e53a163dac8c1c4e84ba94af93ff17714e30255b173796ad0aa8c0bca76f30b1698dd07c83d7c8fa426451c059f410d4f9830cdc951d3daced1ad8d9c4d6586db7356a6eb9059002f966d7975f1bd04192a51eebc97f074d9d801764ae083d46085a622b7bdf1517ea9b991f6dd83a3d038e346273389dd0b4fb1d158360325fb160f20508521f2d50bda75b508018c8ff4c6ada421880084f031d1a2c6bbfc0adf7375aa0b7020f3259ca7761a13bdbd9130c2d8a2de4913714694f3c8de2ad0f3651ff6901bc2fab59f3e45e787aacf95097410314c150af967c820a1e4ca3be9c16de7754892af0c3c997556ce397a4ee216b7b1faff1262539dd96f7b87474740ba82f5e8f411657154db5d052e58d334b1784de9b7e32ca1d3a779d920f0bf52f8c36d06a411392ccfda942ac54acc01cdb83667bc12ad1c9485152e5074da696f2ccf44114ce6534f9f265828162ea1611dfefa34e69d096eb0bf7f6268189e3188cd0d5951b54247304d261e4204c5aa65f872aad8f8763afd68d8331ebbb27bb04bb0bf4893bbe0b2008f305acca6a0546ecf6904234720960e767aec31c97151a67ba0c936337eb06b668ee3c4f822a13a6447e3d2809392ee6598b2f48a81cc8c26ff365d6db28f8efd3666c1c706611033d495199430881e933cec24dbc5b645ab310ac57adc8f5a217d33bd9350ade6c98afff19685ed3b16c4127f458726cb56c6acd4ecd59d4bf17268dd2a7da602256478f5410730dc5b8e43b37e258a7a221f3b0eb602864fd08f9625c263ea9cfb1ae41f907a644718a0f56993930886a9e3ebf35a061a85688799e5c63121c01bf98d98685c0ea3112a5f173a69e08e26b37ee91978760d85de3ada1663d137957972c53f1c88c8c8460d2b69f18128d7cd1b0173eb5e32792dfd6ee479abdc12e9520ce3bba5e8f7</script> <div class="hbe hbe-content"> <div class="hbe hbe-input hbe-input-default"> <input class="hbe hbe-input-field hbe-input-field-default" type="password" id="hbePass"> <label class="hbe hbe-input-label hbe-input-label-default" for="hbePass"> <span class="hbe hbe-input-label-content hbe-input-label-content-default">Hey, password is required here.</span> </label> </div> </div></div><script data-pjax src="/lib/hbe.js"></script><link href="/css/hbe.style.css" rel="stylesheet" type="text/css">]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>碎碎念</title>
<link href="/article/f3404829.html"/>
<url>/article/f3404829.html</url>
<content type="html"><![CDATA[<p>终于要下雨了,孩子要热死了</p><p>什么都不想干,当个废物多好</p><p>今天看到一段话</p><div class="code-wrapper"><pre><code class="hljs">今天37度,我坐在便利店门口抽着烟,看着对面青春飞扬的初中生中考,我才发现我已经离开校园很多年了。可是很奇怪,好像校园青春就在昨天,仿佛天边的云伸手就能摸到。 还是书读得少了,想感慨青春易逝也没感慨出来。只记起陶渊明的一句诗“忆我少壮时,无乐自欣愉。”青春真是充满了力量和脆弱。</code></pre></div><p>今天的壁纸</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/IMG_0108.JPG" alt="IMG_0108"></p><p>杭州一行,玩是没玩明白,倒是回来拉两天肚子,再也不参加这种活动了。</p><p>这次的一些照片。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/ADEEC1E9-BE7F-45B4-A7B8-1046A2827823_1_105_c.jpeg" alt="ADEEC1E9-BE7F-45B4-A7B8-1046A2827823_1_105_c"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/b&bo=VQhABlUIQAYWECA!&rf=viewer_311&t=5" alt="img"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/b&ek=1&kp=1&pt=0&bo=HAtABhwLQAYWECA!&tl=1&vuin=397712823&tm=1656925200&dis_t=1656926146&dis_k=6b61c2a62bf63dc060101c4cca092e03&sce=50-1-1&rf=viewer_311&t=5" alt="img"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/b&ek=1&kp=1&pt=0&bo=VQhABlUIQAYWECA!&tl=1&vuin=397712823&tm=1656925200&dis_t=1656926146&dis_k=4c692d47afb812c710204fd646c7b6c7&sce=50-1-1&rf=viewer_311&t=5" alt="img"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/b&ek=1&kp=1&pt=0&bo=WglABloJQAYWECA!&tl=1&vuin=397712823&tm=1656925200&dis_t=1656926146&dis_k=f340e733aa99e0602f33cfb08e3d7400&sce=50-1-1&rf=viewer_311&t=5" alt="img"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/b&ek=1&kp=1&pt=0&bo=VQhABlUIQAYWECA!&tl=1&vuin=397712823&tm=1656925200&dis_t=1656926146&dis_k=9cf2b2c0b805d5413d4832e9eb42bb0c&sce=50-1-1&rf=viewer_311&t=5" alt="img"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/b&ek=1&kp=1&pt=0&bo=VQhABlUIQAYWECA!&tl=1&vuin=397712823&tm=1656925200&dis_t=1656926146&dis_k=f990c2901268e23184d685220f13f256&sce=50-1-1&rf=viewer_311&t=5" alt="img"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/b&ek=1&kp=1&pt=0&bo=VQhABlUIQAYWECA!&tl=1&vuin=397712823&tm=1656925200&dis_t=1656926146&dis_k=4fda3896c763b8cce7b3abe711690e43&sce=50-1-1&rf=viewer_311&t=5" alt="img"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/b&ek=1&kp=1&pt=0&bo=VQhABlUIQAYWECA!&tl=1&vuin=397712823&tm=1656925200&dis_t=1656926146&dis_k=5d8305503f754517af9f7db63188908e&sce=50-1-1&rf=viewer_311&t=5" alt="img"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/b&ek=1&kp=1&pt=0&bo=VAY4BFQGOAQWECA!&tl=1&vuin=397712823&tm=1656925200&dis_t=1656926146&dis_k=b6fbe529def626514d856cc1c34fda63&sce=50-1-1&rf=viewer_311&t=5" alt="img"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/b&ek=1&kp=1&pt=0&bo=jAhABowIQAYWECA!&tl=1&vuin=397712823&tm=1656925200&dis_t=1656926146&dis_k=cc711e8ed9decbff7c171c8aa071f5ca&sce=50-1-1&rf=viewer_311&t=5" alt="img"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/b&ek=1&kp=1&pt=0&bo=xwdABscHQAYWECA!&tl=1&vuin=397712823&tm=1656925200&dis_t=1656926146&dis_k=69e5ae34acdd4cc32acfe11ad63264b2&sce=50-1-1&rf=viewer_311&t=5" alt="img"></p><p>哦对,女生说暂时不想谈恋爱是指不想跟你谈。记得不要死皮赖脸。</p><hr><p>哎呀终于解封了</p><p>属实是封了快一个月</p><p>让我来显摆一下封控时候搞得能吃的哈哈哈</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202211081134775.jpeg" alt="IMG_1319"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202211081135461.jpg" alt="IMG_1333"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202211081135009.jpg" alt="IMG_1369"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202211081134795.jpg" alt="IMG_1396"></p><p>我觉得还可以哈哈哈</p><p>人一旦宅久了,确实容易废。</p><p>哦对,今晚有月全食,小丫头跟我说那是血月不吉利。</p><p>开玩笑,我可是唯物主义战士。</p><p>每次碎碎念都有好多骚话,却总写不出来。</p><p>算了算了无所谓的。</p><p>最后分享下最近的壁纸吧</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202211081138298.jpg" alt="100174471_p0"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202211081138274.jpg" alt="100191209_p0_master1200"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202211081138266.jpg" alt="100789898_p0"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202211081138336.jpg" alt="101123738_p0"></p><hr><p>好久没有碎碎念了,转眼年关降至,感觉今年啥都干了,又感觉啥都没干,人真是越来越颓了。</p><p>算了,在摸鱼,下次再说。</p>]]></content>
<categories>
<category>杂七杂八的唠叨话</category>
</categories>
</entry>
<entry>
<title>tendaCT6摄像头固件分析</title>
<link href="/article/77f90bb.html"/>
<url>/article/77f90bb.html</url>
<content type="html"><![CDATA[<p>最近逛tenda发现新上了一款摄像头,这不下载个固件看看?</p><p>直接binwalk一把梭</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209271628718.png" alt="image-20220927162813264"></p><h2 id="firmAE"><a href="#firmAE" class="headerlink" title="firmAE"></a>firmAE</h2><p>这里先不看文件系统,尝试下用firmAE来模拟固件</p><blockquote><p>sudo ./run.sh -c ipc /mnt/hgfs/sharedir/tenda/ct6/IPC_SD_update.bin </p><p>需要使用root权限来执行firmAE文件夹下的run.sh,-c参数为check,来检查是否可以模拟,一般check完成后模拟起来会很快,但check很慢,ipc算是项目名字可定义即可</p></blockquote><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209271737716.png" alt="image-20220927173707626"></p><blockquote><p>sudo ./run.sh -d ipc /mnt/hgfs/sharedir/tenda/ct6/IPC_SD_update.bin </p><p>check完成后可以使用 -a参数直接执行,或者-d参数以debug模式执行,debug模式</p></blockquote><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209281348543.png" alt="image-20220928134825377"></p><p>这个固件能模拟,但是不能完全模拟,知道用法就可了。</p><h2 id="如何找到一个固件的服务进行分析"><a href="#如何找到一个固件的服务进行分析" class="headerlink" title="如何找到一个固件的服务进行分析"></a>如何找到一个固件的服务进行分析</h2><p>当解包一个固件的时候发现,没有http服务,没有html页面,没有httpd,boa,uhttpd,lighttpd等。</p><p>某些摄像头经常见到这个问题。</p><p>这个时候需要从启动来一点点看找到他启动了什么服务。</p><p>当然如果有设备并且获取了串口shell,也可以直接查看</p><blockquote><p>这里推荐个超好用的命令 find </p><p>大概用法 </p><p> find . -name “httpd”</p><p> find . -name “*cfg”</p><p>支持*这样的正则匹配</p></blockquote><p>linux启动最先看inittab,一般在etc下面</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209271716514.png" alt="image-20220927171626273"></p><p>启动rcS,一般都在/etc/init.d/rcS</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209271717140.png" alt="image-20220927171715008"></p><p>这里就是执行了init.d文件夹下的文件</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209271718721.png" alt="image-20220927171849636"></p><p>S00devs 里使用mknod创建Linux中的符设备文件和块设备文件,不重要</p><p>S01udev 它主要的功能是管理/dev目录底下的设备节点。它同时也是用来接替devfs及热插拔的功能,这意味着它要在添加/删除硬件时处理/dev目录以及所有用户空间的行为。也不重要</p><p>S80network中也并没有发现启动的服务</p><p>那返回到rcS,执行完S*之后,执行了/opt/app/init.sh</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209271734171.png" alt="image-20220927173417037"></p><p>但opt中没有任何文件,这个时候就需要上面说的find命令了。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209271737692.png" alt="image-20220927173746511"></p><p>吧squashfs-root-0和-1的所有内容移动到opt下</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209271740612.png" alt="image-20220927174017473"></p><p>运行network_setup.sh,启动telnet服务,将execute放到tmp,启动execute服务,运行daemon.sh</p><p>network_setup.sh中没有服务启动,不赘述</p><p>daemon.sh中执行了tdseq服务</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209271747668.png" alt="image-20220927174748489"></p><p>从先后顺序来看,来分析个execute。</p><p>这里tenda摄像头设备基本都是armel,自行file即可</p><h2 id="execute"><a href="#execute" class="headerlink" title="execute"></a>execute</h2><p>main中可以看到socket函数(具体请看socket网络编程)</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209271756484.png" alt="image-20220927175631357"></p><p>这里绑定了8899端口,但是并没有监听。启动下看看</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209271804274.png" alt="image-20220927180401160"></p><p>发现8899的udp协议。</p><p>可以使用netcat连接</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209271806829.png" alt="image-20220927180613667"></p><p>这里分析下udp协议做了什么</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209271810531.png" alt="image-20220927181043433"></p><p>通过recvfrom获取到传入的内容存放到v13,创建新线程将内容传进去。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209271813448.png" alt="image-20220927181335304"></p><p>在线程中,吧参数给了v9,然后注意这个v17获取了前四位做了个判断。</p><p>以为是magicnumber,满足条件执行my_system,但是这个magicnumbe没有做任何奇奇怪怪的判断。</p><p>所以可以直接命令执行,但是还是好奇这个sub_10D64做了什么。</p><p>点进去????????????????????????????</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209281140262.png" alt="image-20220928114023047"></p><p>不是,脱裤子放屁都没这么放的吧。</p><p>开发者这么做,一定有他的用(大)意(病)</p><p>查了半天,也没发现这里if分支的区别。</p><p>这里应该算是个命令执行了。直接来吧(jitang)!</p><h2 id="qemu-user导致的问题"><a href="#qemu-user导致的问题" class="headerlink" title="qemu user导致的问题"></a>qemu user导致的问题</h2><p>这里本来使用的 sudo chroot . ./qemu-arm-static ./opt/app/execute 启动的,但是命令执行死活不成功。</p><p>gdb调试了一天,愣是没找到问题。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209281154380.png" alt="image-20220928115439112"></p><p>第二天尝试了下qemu-arm-static -L . ./opt/app/execute</p><p>可以了。。。,这里xxxx就是为了填充magic number,可以写脚本传入0x00来执行到sub函数。</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209281158099.png" alt="image-20220928115801001"></p><p>所以各位有时候遇到这种问题可以看一下是否是qemu的问题。</p><p>当然,如果像我一样,有一个同架构的其他设备,又刚好有该设备的rce,就可以搞点牛头人操作了。</p><h2 id="关于gdb多线程调试"><a href="#关于gdb多线程调试" class="headerlink" title="关于gdb多线程调试"></a>关于gdb多线程调试</h2><p>gdb多线程调试,大概说一下怎么搞。</p><p>使用qemu自带的-g参数启动远程server</p><blockquote><p> qemu-arm-static -L . -g 1234 ./opt/app/execute # 1234为监听的端口</p></blockquote><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209281402057.png" alt="image-20220928140246774"></p><p>使用gdb-multiarch来进行调试</p><blockquote><p>gdb-multiarch opt/app/execute</p><p>target remote 127.0.0.1</p></blockquote><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209281407294.png" alt="image-20220928140716065"></p><p>在子线程函数中下个断点,我这边位置是0x000110E8</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209281409052.png" alt="image-20220928140942865"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209281409246.png" alt="image-20220928140953173"></p><p>使用c来执行程序</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209281410262.png" alt="image-20220928141028136"></p><p>使用netcat连接udp</p><blockquote><p>nc -uvv 127.0.0.1 8899</p></blockquote><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209281411690.png" alt="image-20220928141124554"></p><p>连上后gdb中能发现新线程</p><blockquote><p>info threads</p></blockquote><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209281414198.png" alt="image-20220928141434051"></p><p>ID 2 就是断下来的心线程,使用thread 2来切换线程</p><blockquote><p>thread 2</p></blockquote><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image@main/202209281415439.png" alt="image-20220928141540348"></p><p>此时pc指向我们的断点,要回主线程,只需要再次切换即可。</p>]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>协议-rtsp</title>
<link href="/article/ccd0d78.html"/>
<url>/article/ccd0d78.html</url>
<content type="html"><![CDATA[<p>最近在看摄像头,刚好碰到rtsp协议的东西,寻思学习记录下。</p><p>这里csdn的<a href="https://blog.csdn.net/weixin_42462202">JT同学</a>师傅的博客写的很不错。</p><p>rtsp是一个实时传输流协议,简单点说就是用来看视频的。</p><p>rtsp通常包括rtp,rtcp,rtsp</p><blockquote><p>rtsp负责客户端与服务端的请求和响应</p><p>rtcp负责在RTP传输过程中提供传输信息</p><p>rtp负责传输媒体数据</p><p>rtsp承载与rtp和rtcp之上,rtsp并不会发送媒体数据,而是使用rtp协议传输</p><p>rtp并没有规定发送方式,可以选择udp发送或者tcp发送</p></blockquote><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220822110639937.png" alt="image-20220822110639937"></p>]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>协议-tinyhttpd</title>
<link href="/article/68d281b.html"/>
<url>/article/68d281b.html</url>
<content type="html"><![CDATA[<p>一个非常轻量的httpd服务器,只有500行代码。</p><p>我后边用python写了一个很简陋的几十行代码的,可以看下那个来简单看一下。</p><p>这里只看了网络编程的一些东西,进程通信挖个坑,下次填。</p><p>很适合</p><blockquote><p><a href="https://github.com/EZLippi/Tinyhttpd.git">https://github.com/EZLippi/Tinyhttpd.git</a></p><p>编译方式是直接make</p></blockquote><p>编译执行后发现开启4000端口</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220720153445595.png" alt="image-20220720153445595"></p><p>默认加载htdocs下的index.html</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220720154305858.png" alt="image-20220720154305858"></p><p>当去访问一个不存在的文件a.html</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220720154327199.png" alt="image-20220720154327199"></p><p>cgi问题</p><p>这里写一个简单的shell cgi来替代自带的cgi</p><div class="code-wrapper"><pre><code class="hljs sh"><span class="hljs-meta">#!/bin/bash</span><span class="hljs-built_in">echo</span> <span class="hljs-string">"Content-Type: text/html"</span><span class="hljs-built_in">echo</span><span class="hljs-built_in">echo</span> <span class="hljs-string">"<HTML><BODY>"</span><span class="hljs-built_in">echo</span> <span class="hljs-string">"<CENTER>Today is:</CENTER>"</span><span class="hljs-built_in">echo</span> <span class="hljs-string">"<CENTER><B>"</span><span class="hljs-built_in">date</span><span class="hljs-built_in">echo</span> <span class="hljs-string">"</B></CENTER>"</span><span class="hljs-built_in">echo</span> <span class="hljs-string">"</BODY></HTML>"</span></code></pre></div><p>访问cgi文件,发现cgi并未被执行</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220720160433477.png" alt="image-20220720160433477"></p><p>是因为没有执行权限,所以导致直接被当成静态文件,而有执行权限的话,静态文件也会被当作cgi执行。</p><p>尝试将所有的文件赋予权限</p><blockquote><p>chmod 777 ./*</p></blockquote><p>index页面无法正常显示</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220720155641576.png" alt="image-20220720155641576"></p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220720160541100.png" alt="image-20220720160541100"></p><p>执行方式可以通过下图来理解</p><p><img src="https://cdn.jsdelivr.net/gh/p1yang/image/image-20220720152650036.png" alt="image-20220720152650036"></p><h2 id="注释代码"><a href="#注释代码" class="headerlink" title="注释代码"></a>注释代码</h2><p>项目放代码阅读时的代码放gitee了需要可自行下载:<a href="https://gitee.com/p1piyang/backward-analysis/">https://gitee.com/p1piyang/backward-analysis/</a></p><div class="code-wrapper"><pre><code class="hljs c"><span class="hljs-comment">/* J. David's webserver */</span><span class="hljs-comment">/* This is a simple webserver.</span><span class="hljs-comment"> * Created November 1999 by J. David Blackstone.</span><span class="hljs-comment"> * CSE 4344 (Network concepts), Prof. Zeigler</span><span class="hljs-comment"> * University of Texas at Arlington</span><span class="hljs-comment"> */</span><span class="hljs-comment">/* This program compiles for Sparc Solaris 2.6.</span><span class="hljs-comment"> * To compile for Linux:</span><span class="hljs-comment"> * 1) Comment out the #include <pthread.h> line.</span><span class="hljs-comment"> * 2) Comment out the line that defines the variable newthread.</span><span class="hljs-comment"> * 3) Comment out the two lines that run pthread_create().</span><span class="hljs-comment"> * 4) Uncomment the line that runs accept_request().</span><span class="hljs-comment"> * 5) Remove -lsocket from the Makefile.</span><span class="hljs-comment"> */</span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdio.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><sys/socket.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><sys/types.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><netinet/in.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><arpa/inet.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><unistd.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><ctype.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><strings.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><string.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><sys/stat.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><pthread.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><sys/wait.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdlib.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdint.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">define</span> ISspace(x) isspace((int)(x))</span><span class="hljs-meta">#<span class="hljs-keyword">define</span> SERVER_STRING <span class="hljs-string">"Server: jdbhttpd/0.1.0\r\n"</span></span><span class="hljs-meta">#<span class="hljs-keyword">define</span> STDIN 0</span><span class="hljs-meta">#<span class="hljs-keyword">define</span> STDOUT 1</span><span class="hljs-meta">#<span class="hljs-keyword">define</span> STDERR 2</span><span class="hljs-type">void</span> <span class="hljs-title function_">accept_request</span><span class="hljs-params">(<span class="hljs-type">void</span> *)</span>;<span class="hljs-type">void</span> <span class="hljs-title function_">bad_request</span><span class="hljs-params">(<span class="hljs-type">int</span>)</span>;<span class="hljs-type">void</span> <span class="hljs-title function_">cat</span><span class="hljs-params">(<span class="hljs-type">int</span>, FILE *)</span>;<span class="hljs-type">void</span> <span class="hljs-title function_">cannot_execute</span><span class="hljs-params">(<span class="hljs-type">int</span>)</span>;<span class="hljs-type">void</span> <span class="hljs-title function_">error_die</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span> *)</span>;<span class="hljs-type">void</span> <span class="hljs-title function_">execute_cgi</span><span class="hljs-params">(<span class="hljs-type">int</span>, <span class="hljs-type">const</span> <span class="hljs-type">char</span> *, <span class="hljs-type">const</span> <span class="hljs-type">char</span> *, <span class="hljs-type">const</span> <span class="hljs-type">char</span> *)</span>;<span class="hljs-type">int</span> <span class="hljs-title function_">get_line</span><span class="hljs-params">(<span class="hljs-type">int</span>, <span class="hljs-type">char</span> *, <span class="hljs-type">int</span>)</span>;<span class="hljs-type">void</span> <span class="hljs-title function_">headers</span><span class="hljs-params">(<span class="hljs-type">int</span>, <span class="hljs-type">const</span> <span class="hljs-type">char</span> *)</span>;<span class="hljs-type">void</span> <span class="hljs-title function_">not_found</span><span class="hljs-params">(<span class="hljs-type">int</span>)</span>;<span class="hljs-type">void</span> <span class="hljs-title function_">serve_file</span><span class="hljs-params">(<span class="hljs-type">int</span>, <span class="hljs-type">const</span> <span class="hljs-type">char</span> *)</span>;<span class="hljs-type">int</span> <span class="hljs-title function_">startup</span><span class="hljs-params">(u_short *)</span>;<span class="hljs-type">void</span> <span class="hljs-title function_">unimplemented</span><span class="hljs-params">(<span class="hljs-type">int</span>)</span>;<span class="hljs-comment">/**********************************************************************/</span><span class="hljs-comment">/* A request has caused a call to accept() on the server port to</span><span class="hljs-comment"> * return. Process the request appropriately.</span><span class="hljs-comment"> * Parameters: the socket connected to the client */</span><span class="hljs-comment">/**********************************************************************/</span><span class="hljs-type">void</span> <span class="hljs-title function_">accept_request</span><span class="hljs-params">(<span class="hljs-type">void</span> *arg)</span>{ <span class="hljs-type">int</span> client = (<span class="hljs-type">intptr_t</span>)arg; <span class="hljs-type">char</span> buf[<span class="hljs-number">1024</span>]; <span class="hljs-type">size_t</span> numchars; <span class="hljs-type">char</span> method[<span class="hljs-number">255</span>]; <span class="hljs-type">char</span> url[<span class="hljs-number">255</span>]; <span class="hljs-type">char</span> path[<span class="hljs-number">512</span>]; <span class="hljs-type">size_t</span> i, j; <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">stat</span> <span class="hljs-title">st</span>;</span> <span class="hljs-comment">//文件信息</span> <span class="hljs-comment">//struct stat{</span> <span class="hljs-comment">// dev_t st_dev; /* ID of device containing file */文件使用的设备号</span> <span class="hljs-comment">// ino_t st_ino; /* inode number */ 索引节点号 </span> <span class="hljs-comment">// mode_t st_mode; /* protection */ 文件对应的模式,文件,目录等</span> <span class="hljs-comment">// nlink_t st_nlink; /* number of hard links */ 文件的硬连接数 </span> <span class="hljs-comment">// uid_t st_uid; /* user ID of owner */ 所有者用户识别号</span> <span class="hljs-comment">// gid_t st_gid; /* group ID of owner */ 组识别号 </span> <span class="hljs-comment">// dev_t st_rdev; /* device ID (if special file) */ 设备文件的设备号</span> <span class="hljs-comment">// off_t st_size; /* total size, in bytes */ 以字节为单位的文件容量 </span> <span class="hljs-comment">// blksize_t st_blksize; /* blocksize for file system I/O */ 包含该文件的磁盘块的大小 </span> <span class="hljs-comment">// blkcnt_t st_blocks; /* number of 512B blocks allocated */ 该文件所占的磁盘块 </span> <span class="hljs-comment">// time_t st_atime; /* time of last access */ 最后一次访问该文件的时间 </span> <span class="hljs-comment">// time_t st_mtime; /* time of last modification */ /最后一次修改该文件的时间 </span> <span class="hljs-comment">// time_t st_ctime; /* time of last status change */ 最后一次改变该文件状态的时间 </span> <span class="hljs-comment">//};</span> <span class="hljs-type">int</span> cgi = <span class="hljs-number">0</span>; <span class="hljs-comment">/* becomes true if server decides this is a CGI</span><span class="hljs-comment"> * program */</span> <span class="hljs-type">char</span> *query_string = <span class="hljs-literal">NULL</span>; <span class="hljs-comment">//读取http请求的第一行数据</span> numchars = get_line(client, buf, <span class="hljs-keyword">sizeof</span>(buf)); i = <span class="hljs-number">0</span>; j = <span class="hljs-number">0</span>; <span class="hljs-comment">//吧请求方法存到,,method中</span> <span class="hljs-keyword">while</span> (!ISspace(buf[i]) && (i < <span class="hljs-keyword">sizeof</span>(method) - <span class="hljs-number">1</span>)) { method[i] = buf[i]; i++; } j=i; method[i] = <span class="hljs-string">'\0'</span>; <span class="hljs-comment">//判断如果不是get或者post方法,发送response给客户端表示无法实现</span> <span class="hljs-keyword">if</span> (strcasecmp(method, <span class="hljs-string">"GET"</span>) && strcasecmp(method, <span class="hljs-string">"POST"</span>)) { <span class="hljs-comment">//使用sprintf函数将要返回的内容给buf,使用send函数返回给client</span> unimplemented(client); <span class="hljs-keyword">return</span>; } <span class="hljs-comment">//判断为post方法</span> <span class="hljs-keyword">if</span> (strcasecmp(method, <span class="hljs-string">"POST"</span>) == <span class="hljs-number">0</span>) cgi = <span class="hljs-number">1</span>; i = <span class="hljs-number">0</span>; <span class="hljs-comment">//跳过空格</span> <span class="hljs-keyword">while</span> (ISspace(buf[j]) && (j < numchars)) j++; <span class="hljs-comment">//获取url</span> <span class="hljs-keyword">while</span> (!ISspace(buf[j]) && (i < <span class="hljs-keyword">sizeof</span>(url) - <span class="hljs-number">1</span>) && (j < numchars)) { url[i] = buf[j]; i++; j++; } url[i] = <span class="hljs-string">'\0'</span>; <span class="hljs-comment">//get方法</span> <span class="hljs-keyword">if</span> (strcasecmp(method, <span class="hljs-string">"GET"</span>) == <span class="hljs-number">0</span>) { query_string = url; <span class="hljs-comment">//用于记录带参数的GET方法请求中 ‘?’后的参数</span> <span class="hljs-keyword">while</span> ((*query_string != <span class="hljs-string">'?'</span>) && (*query_string != <span class="hljs-string">'\0'</span>)) query_string++; <span class="hljs-keyword">if</span> (*query_string == <span class="hljs-string">'?'</span>) { cgi = <span class="hljs-number">1</span>; *query_string = <span class="hljs-string">'\0'</span>; query_string++; } } <span class="hljs-comment">//将htdocs与url拼接到一起给path,即我们的资源文件都在htdocs下</span> <span class="hljs-built_in">sprintf</span>(path, <span class="hljs-string">"htdocs%s"</span>, url); <span class="hljs-comment">//判断如果URL的最后一位是‘/’,加上index.html</span> <span class="hljs-keyword">if</span> (path[<span class="hljs-built_in">strlen</span>(path) - <span class="hljs-number">1</span>] == <span class="hljs-string">'/'</span>) <span class="hljs-built_in">strcat</span>(path, <span class="hljs-string">"index.html"</span>); <span class="hljs-comment">//定义函数:int stat(const char * file_name, struct stat *buf);</span> <span class="hljs-comment">//函数说明:stat()用来将参数file_name 所指的文件状态, 复制到参数buf 所指的结构中。</span> <span class="hljs-comment">//返回值:执行成功则返回0,失败返回-1,错误代码存于errno。 </span> <span class="hljs-comment">//这里改了一下,把东西处理下可以看到是处理包头。</span> <span class="hljs-comment">//根据执行来看,这个if判断</span> <span class="hljs-keyword">if</span> (stat(path, &st) == <span class="hljs-number">-1</span>) { <span class="hljs-keyword">while</span> ((numchars > <span class="hljs-number">0</span>) && <span class="hljs-built_in">strcmp</span>(<span class="hljs-string">"\n"</span>, buf)) <span class="hljs-comment">/* read & discard headers */</span> { numchars = get_line(client, buf, <span class="hljs-keyword">sizeof</span>(buf)); <span class="hljs-type">char</span> *test = buf; <span class="hljs-built_in">printf</span>(<span class="hljs-string">"for: %s"</span>, test); } <span class="hljs-comment">//打印404返回页面</span> not_found(client); } <span class="hljs-keyword">else</span> { <span class="hljs-comment">// 文件存在,那则跟常量S_IFMT相与,相与之后的值可以用来判断该文件是什么类型的</span> <span class="hljs-comment">// 此处与上边判断路径是不是以 \ 结尾的地方作用一样,可以省略,留着可重复确认。</span> <span class="hljs-keyword">if</span> ((st.st_mode & S_IFMT) == S_IFDIR) <span class="hljs-built_in">strcat</span>(path, <span class="hljs-string">"/index.html"</span>); <span class="hljs-comment">//判断权限的,前面有说过的</span> <span class="hljs-keyword">if</span> ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH) ) cgi = <span class="hljs-number">1</span>; <span class="hljs-keyword">if</span> (!cgi) { <span class="hljs-built_in">printf</span>(<span class="hljs-string">"nocgi\n"</span>); <span class="hljs-comment">//不需要cgi的</span> serve_file(client, path); } <span class="hljs-keyword">else</span> { <span class="hljs-comment">//需要cgi的</span> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"cgi\n"</span>); execute_cgi(client, path, method, query_string); } } close(client);}<span class="hljs-comment">/**********************************************************************/</span><span class="hljs-comment">/* Inform the client that a request it has made has a problem.</span><span class="hljs-comment"> * Parameters: client socket */</span><span class="hljs-comment">/**********************************************************************/</span><span class="hljs-type">void</span> <span class="hljs-title function_">bad_request</span><span class="hljs-params">(<span class="hljs-type">int</span> client)</span>{ <span class="hljs-type">char</span> buf[<span class="hljs-number">1024</span>]; <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"HTTP/1.0 400 BAD REQUEST\r\n"</span>); send(client, buf, <span class="hljs-keyword">sizeof</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"Content-type: text/html\r\n"</span>); send(client, buf, <span class="hljs-keyword">sizeof</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"\r\n"</span>); send(client, buf, <span class="hljs-keyword">sizeof</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"<P>Your browser sent a bad request, "</span>); send(client, buf, <span class="hljs-keyword">sizeof</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"such as a POST without a Content-Length.\r\n"</span>); send(client, buf, <span class="hljs-keyword">sizeof</span>(buf), <span class="hljs-number">0</span>);}<span class="hljs-comment">/**********************************************************************/</span><span class="hljs-comment">/* Put the entire contents of a file out on a socket. This function</span><span class="hljs-comment"> * is named after the UNIX "cat" command, because it might have been</span><span class="hljs-comment"> * easier just to do something like pipe, fork, and exec("cat").</span><span class="hljs-comment"> * Parameters: the client socket descriptor</span><span class="hljs-comment"> * FILE pointer for the file to cat */</span><span class="hljs-comment">/**********************************************************************/</span><span class="hljs-type">void</span> <span class="hljs-title function_">cat</span><span class="hljs-params">(<span class="hljs-type">int</span> client, FILE *resource)</span>{ <span class="hljs-type">char</span> buf[<span class="hljs-number">1024</span>]; <span class="hljs-comment">//读取文件内容,发送到前端。</span> fgets(buf, <span class="hljs-keyword">sizeof</span>(buf), resource); <span class="hljs-keyword">while</span> (!feof(resource)) { send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); fgets(buf, <span class="hljs-keyword">sizeof</span>(buf), resource); }}<span class="hljs-comment">/**********************************************************************/</span><span class="hljs-comment">/* Inform the client that a CGI script could not be executed.</span><span class="hljs-comment"> * Parameter: the client socket descriptor. */</span><span class="hljs-comment">/**********************************************************************/</span><span class="hljs-type">void</span> <span class="hljs-title function_">cannot_execute</span><span class="hljs-params">(<span class="hljs-type">int</span> client)</span>{ <span class="hljs-type">char</span> buf[<span class="hljs-number">1024</span>]; <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"HTTP/1.0 500 Internal Server Error\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"Content-type: text/html\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"<P>Error prohibited CGI execution.\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>);}<span class="hljs-comment">/**********************************************************************/</span><span class="hljs-comment">/* Print out an error message with perror() (for system errors; based</span><span class="hljs-comment"> * on value of errno, which indicates system call errors) and exit the</span><span class="hljs-comment"> * program indicating an error. */</span><span class="hljs-comment">/**********************************************************************/</span><span class="hljs-type">void</span> <span class="hljs-title function_">error_die</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span> *sc)</span>{ perror(sc); <span class="hljs-built_in">exit</span>(<span class="hljs-number">1</span>);}<span class="hljs-comment">/**********************************************************************/</span><span class="hljs-comment">/* Execute a CGI script. Will need to set environment variables as</span><span class="hljs-comment"> * appropriate.</span><span class="hljs-comment"> * Parameters: client socket descriptor</span><span class="hljs-comment"> * path to the CGI script */</span><span class="hljs-comment">/**********************************************************************/</span> <span class="hljs-comment">// cgi用于动态网页的处理</span> <span class="hljs-comment">// execute_cgi函数创建了两个进程,子进程用于cgi文件的处理,父进程用于往socket读写数据</span><span class="hljs-type">void</span> <span class="hljs-title function_">execute_cgi</span><span class="hljs-params">(<span class="hljs-type">int</span> client, <span class="hljs-type">const</span> <span class="hljs-type">char</span> *path,</span><span class="hljs-params"> <span class="hljs-type">const</span> <span class="hljs-type">char</span> *method, <span class="hljs-type">const</span> <span class="hljs-type">char</span> *query_string)</span>{ <span class="hljs-type">char</span> buf[<span class="hljs-number">1024</span>]; <span class="hljs-type">int</span> cgi_output[<span class="hljs-number">2</span>]; <span class="hljs-type">int</span> cgi_input[<span class="hljs-number">2</span>]; <span class="hljs-type">pid_t</span> pid; <span class="hljs-type">int</span> status; <span class="hljs-type">int</span> i; <span class="hljs-type">char</span> c; <span class="hljs-type">int</span> numchars = <span class="hljs-number">1</span>; <span class="hljs-type">int</span> content_length = <span class="hljs-number">-1</span>; buf[<span class="hljs-number">0</span>] = <span class="hljs-string">'A'</span>; buf[<span class="hljs-number">1</span>] = <span class="hljs-string">'\0'</span>; <span class="hljs-built_in">printf</span>(<span class="hljs-string">">exec cgi\n"</span>); <span class="hljs-comment">//get方法</span> <span class="hljs-keyword">if</span> (strcasecmp(method, <span class="hljs-string">"GET"</span>) == <span class="hljs-number">0</span>) <span class="hljs-keyword">while</span> ((numchars > <span class="hljs-number">0</span>) && <span class="hljs-built_in">strcmp</span>(<span class="hljs-string">"\n"</span>, buf)) <span class="hljs-comment">/* read & discard headers */</span> { <span class="hljs-built_in">printf</span>(<span class="hljs-string">">get\n"</span>); numchars = get_line(client, buf, <span class="hljs-keyword">sizeof</span>(buf)); } <span class="hljs-comment">//post方法</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (strcasecmp(method, <span class="hljs-string">"POST"</span>) == <span class="hljs-number">0</span>) <span class="hljs-comment">/*POST*/</span> { numchars = get_line(client, buf, <span class="hljs-keyword">sizeof</span>(buf)); <span class="hljs-keyword">while</span> ((numchars > <span class="hljs-number">0</span>) && <span class="hljs-built_in">strcmp</span>(<span class="hljs-string">"\n"</span>, buf)) { <span class="hljs-comment">// "Content-Length:"长度为15个字符,所以将前15个字符比较。 </span> buf[<span class="hljs-number">15</span>] = <span class="hljs-string">'\0'</span>; <span class="hljs-comment">// 如果是Content-Length,读取这个改字段转为整数</span> <span class="hljs-keyword">if</span> (strcasecmp(buf, <span class="hljs-string">"Content-Length:"</span>) == <span class="hljs-number">0</span>) { content_length = atoi(&(buf[<span class="hljs-number">16</span>])); <span class="hljs-built_in">printf</span>(<span class="hljs-string">"lenght:%d\n"</span>,content_length); } numchars = get_line(client, buf, <span class="hljs-keyword">sizeof</span>(buf)); } <span class="hljs-comment">//无法处理的话,400错误</span> <span class="hljs-keyword">if</span> (content_length == <span class="hljs-number">-1</span>) { bad_request(client); <span class="hljs-keyword">return</span>; } } <span class="hljs-keyword">else</span><span class="hljs-comment">/*HEAD or other*/</span> { } <span class="hljs-comment">//创建管道</span> <span class="hljs-comment">//子进程写管道</span> <span class="hljs-keyword">if</span> (pipe(cgi_output) < <span class="hljs-number">0</span>) { <span class="hljs-comment">//服务错误500</span> cannot_execute(client); <span class="hljs-keyword">return</span>; } <span class="hljs-comment">//子进程写管道</span> <span class="hljs-keyword">if</span> (pipe(cgi_input) < <span class="hljs-number">0</span>) { <span class="hljs-comment">//服务错误500</span> cannot_execute(client); <span class="hljs-keyword">return</span>; } <span class="hljs-comment">//创建子进程</span> <span class="hljs-keyword">if</span> ( (pid = fork()) < <span class="hljs-number">0</span> ) { cannot_execute(client); <span class="hljs-keyword">return</span>; } <span class="hljs-comment">//响应成功</span> <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"HTTP/1.0 200 OK\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-comment">// 这下面是另一个坑,进程通信。</span> <span class="hljs-keyword">if</span> (pid == <span class="hljs-number">0</span>) <span class="hljs-comment">/* child: CGI script */</span> { <span class="hljs-type">char</span> meth_env[<span class="hljs-number">255</span>]; <span class="hljs-type">char</span> query_env[<span class="hljs-number">255</span>]; <span class="hljs-type">char</span> length_env[<span class="hljs-number">255</span>]; dup2(cgi_output[<span class="hljs-number">1</span>], STDOUT); dup2(cgi_input[<span class="hljs-number">0</span>], STDIN); close(cgi_output[<span class="hljs-number">0</span>]); close(cgi_input[<span class="hljs-number">1</span>]); <span class="hljs-built_in">sprintf</span>(meth_env, <span class="hljs-string">"REQUEST_METHOD=%s"</span>, method); putenv(meth_env); <span class="hljs-keyword">if</span> (strcasecmp(method, <span class="hljs-string">"GET"</span>) == <span class="hljs-number">0</span>) { <span class="hljs-built_in">sprintf</span>(query_env, <span class="hljs-string">"QUERY_STRING=%s"</span>, query_string); putenv(query_env); } <span class="hljs-keyword">else</span> { <span class="hljs-comment">/* POST */</span> <span class="hljs-built_in">sprintf</span>(length_env, <span class="hljs-string">"CONTENT_LENGTH=%d"</span>, content_length); putenv(length_env); } execl(path, <span class="hljs-literal">NULL</span>); <span class="hljs-built_in">exit</span>(<span class="hljs-number">0</span>); } <span class="hljs-keyword">else</span> { <span class="hljs-comment">/* parent */</span> close(cgi_output[<span class="hljs-number">1</span>]); close(cgi_input[<span class="hljs-number">0</span>]); <span class="hljs-keyword">if</span> (strcasecmp(method, <span class="hljs-string">"POST"</span>) == <span class="hljs-number">0</span>) <span class="hljs-keyword">for</span> (i = <span class="hljs-number">0</span>; i < content_length; i++) { recv(client, &c, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>); write(cgi_input[<span class="hljs-number">1</span>], &c, <span class="hljs-number">1</span>); } <span class="hljs-keyword">while</span> (read(cgi_output[<span class="hljs-number">0</span>], &c, <span class="hljs-number">1</span>) > <span class="hljs-number">0</span>) send(client, &c, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>); close(cgi_output[<span class="hljs-number">0</span>]); close(cgi_input[<span class="hljs-number">1</span>]); waitpid(pid, &status, <span class="hljs-number">0</span>); }}<span class="hljs-comment">/**********************************************************************/</span><span class="hljs-comment">/* Get a line from a socket, whether the line ends in a newline,</span><span class="hljs-comment"> * carriage return, or a CRLF combination. Terminates the string read</span><span class="hljs-comment"> * with a null character. If no newline indicator is found before the</span><span class="hljs-comment"> * end of the buffer, the string is terminated with a null. If any of</span><span class="hljs-comment"> * the above three line terminators is read, the last character of the</span><span class="hljs-comment"> * string will be a linefeed and the string will be terminated with a</span><span class="hljs-comment"> * null character.</span><span class="hljs-comment"> * Parameters: the socket descriptor</span><span class="hljs-comment"> * the buffer to save the data in</span><span class="hljs-comment"> * the size of the buffer</span><span class="hljs-comment"> * Returns: the number of bytes stored (excluding null) */</span><span class="hljs-comment">/**********************************************************************/</span><span class="hljs-comment">//处理包,大概流程是循环读取每个字符</span><span class="hljs-comment">//如果回车符(\r)的后面不是换行符(\n)或者读取失败就把当前读取的字符置为换行,从而终止循环</span><span class="hljs-comment">//如果没有成功接收到字符,以 \n 结尾,结束循环</span><span class="hljs-comment">//最后以\n结尾</span><span class="hljs-type">int</span> <span class="hljs-title function_">get_line</span><span class="hljs-params">(<span class="hljs-type">int</span> sock, <span class="hljs-type">char</span> *buf, <span class="hljs-type">int</span> size)</span>{ <span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; <span class="hljs-type">char</span> c = <span class="hljs-string">'\0'</span>; <span class="hljs-type">int</span> n; <span class="hljs-comment">//</span> <span class="hljs-keyword">while</span> ((i < size - <span class="hljs-number">1</span>) && (c != <span class="hljs-string">'\n'</span>)) { n = recv(sock, &c, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>); <span class="hljs-comment">/* DEBUG printf("%02X\n", c); */</span> <span class="hljs-keyword">if</span> (n > <span class="hljs-number">0</span>) { <span class="hljs-keyword">if</span> (c == <span class="hljs-string">'\r'</span>) { n = recv(sock, &c, <span class="hljs-number">1</span>, MSG_PEEK); <span class="hljs-comment">/* DEBUG printf("%02X\n", c); */</span> <span class="hljs-keyword">if</span> ((n > <span class="hljs-number">0</span>) && (c == <span class="hljs-string">'\n'</span>)) recv(sock, &c, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>); <span class="hljs-keyword">else</span> c = <span class="hljs-string">'\n'</span>; } buf[i] = c; i++; } <span class="hljs-keyword">else</span> c = <span class="hljs-string">'\n'</span>; } buf[i] = <span class="hljs-string">'\0'</span>; <span class="hljs-keyword">return</span>(i);}<span class="hljs-comment">/**********************************************************************/</span><span class="hljs-comment">/* Return the informational HTTP headers about a file. */</span><span class="hljs-comment">/* Parameters: the socket to print the headers on</span><span class="hljs-comment"> * the name of the file */</span><span class="hljs-comment">/**********************************************************************/</span><span class="hljs-comment">//响应头</span><span class="hljs-type">void</span> <span class="hljs-title function_">headers</span><span class="hljs-params">(<span class="hljs-type">int</span> client, <span class="hljs-type">const</span> <span class="hljs-type">char</span> *filename)</span>{ <span class="hljs-type">char</span> buf[<span class="hljs-number">1024</span>]; (<span class="hljs-type">void</span>)filename; <span class="hljs-comment">/* could use filename to determine file type */</span> <span class="hljs-built_in">strcpy</span>(buf, <span class="hljs-string">"HTTP/1.0 200 OK\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">strcpy</span>(buf, SERVER_STRING); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"Content-Type: text/html\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">strcpy</span>(buf, <span class="hljs-string">"\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>);}<span class="hljs-comment">/**********************************************************************/</span><span class="hljs-comment">/* Give a client a 404 not found status message. */</span><span class="hljs-comment">/**********************************************************************/</span><span class="hljs-type">void</span> <span class="hljs-title function_">not_found</span><span class="hljs-params">(<span class="hljs-type">int</span> client)</span>{ <span class="hljs-comment">//将内容打印到缓存,并且发送出去</span> <span class="hljs-type">char</span> buf[<span class="hljs-number">1024</span>]; <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"HTTP/1.0 404 NOT FOUND\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, SERVER_STRING); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"Content-Type: text/html\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"<HTML><TITLE>Not Found</TITLE>\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"<BODY><P>The server could not fulfill\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"your request because the resource specified\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"is unavailable or nonexistent.\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"</BODY></HTML>\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>);}<span class="hljs-comment">/**********************************************************************/</span><span class="hljs-comment">/* Send a regular file to the client. Use headers, and report</span><span class="hljs-comment"> * errors to client if they occur.</span><span class="hljs-comment"> * Parameters: a pointer to a file structure produced from the socket</span><span class="hljs-comment"> * file descriptor</span><span class="hljs-comment"> * the name of the file to serve */</span><span class="hljs-comment">/**********************************************************************/</span><span class="hljs-type">void</span> <span class="hljs-title function_">serve_file</span><span class="hljs-params">(<span class="hljs-type">int</span> client, <span class="hljs-type">const</span> <span class="hljs-type">char</span> *filename)</span>{ FILE *resource = <span class="hljs-literal">NULL</span>; <span class="hljs-type">int</span> numchars = <span class="hljs-number">1</span>; <span class="hljs-type">char</span> buf[<span class="hljs-number">1024</span>]; buf[<span class="hljs-number">0</span>] = <span class="hljs-string">'A'</span>; buf[<span class="hljs-number">1</span>] = <span class="hljs-string">'\0'</span>; <span class="hljs-keyword">while</span> ((numchars > <span class="hljs-number">0</span>) && <span class="hljs-built_in">strcmp</span>(<span class="hljs-string">"\n"</span>, buf)) <span class="hljs-comment">/* read & discard headers */</span> numchars = get_line(client, buf, <span class="hljs-keyword">sizeof</span>(buf)); <span class="hljs-comment">//打开文件,判断是否有文件</span> resource = fopen(filename, <span class="hljs-string">"r"</span>); <span class="hljs-keyword">if</span> (resource == <span class="hljs-literal">NULL</span>) not_found(client); <span class="hljs-keyword">else</span> { <span class="hljs-comment">//构造响应头给客户端</span> headers(client, filename); <span class="hljs-comment">//将文件内容发送给客户端</span> cat(client, resource); } fclose(resource);}<span class="hljs-comment">/**********************************************************************/</span><span class="hljs-comment">/* This function starts the process of listening for web connections</span><span class="hljs-comment"> * on a specified port. If the port is 0, then dynamically allocate a</span><span class="hljs-comment"> * port and modify the original port variable to reflect the actual</span><span class="hljs-comment"> * port.</span><span class="hljs-comment"> * Parameters: pointer to variable containing the port to connect on</span><span class="hljs-comment"> * Returns: the socket */</span><span class="hljs-comment">/**********************************************************************/</span><span class="hljs-comment">//初始化 httpd 服务,包括建立套接字,绑定端口,进行监听等。</span><span class="hljs-type">int</span> <span class="hljs-title function_">startup</span><span class="hljs-params">(u_short *port)</span>{ <span class="hljs-type">int</span> httpd = <span class="hljs-number">0</span>; <span class="hljs-type">int</span> on = <span class="hljs-number">1</span>; <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">sockaddr_in</span> <span class="hljs-title">name</span>;</span> <span class="hljs-comment">//正常的socket创建流程</span> httpd = socket(PF_INET, SOCK_STREAM, <span class="hljs-number">0</span>); <span class="hljs-keyword">if</span> (httpd == <span class="hljs-number">-1</span>) error_die(<span class="hljs-string">"socket"</span>); <span class="hljs-built_in">memset</span>(&name, <span class="hljs-number">0</span>, <span class="hljs-keyword">sizeof</span>(name)); name.sin_family = AF_INET; name.sin_port = htons(*port); name.sin_addr.s_addr = htonl(INADDR_ANY); <span class="hljs-comment">//setsockopt()函数,用于任意类型、任意状态套接口的设置选项值 </span> <span class="hljs-keyword">if</span> ((setsockopt(httpd, SOL_SOCKET, SO_REUSEADDR, &on, <span class="hljs-keyword">sizeof</span>(on))) < <span class="hljs-number">0</span>) { error_die(<span class="hljs-string">"setsockopt failed"</span>); } <span class="hljs-comment">//绑定socket到端口,port等于0,系统会随机分配一个端口(bind函数里实现)</span> <span class="hljs-keyword">if</span> (bind(httpd, (<span class="hljs-keyword">struct</span> sockaddr *)&name, <span class="hljs-keyword">sizeof</span>(name)) < <span class="hljs-number">0</span>) error_die(<span class="hljs-string">"bind"</span>); <span class="hljs-comment">// 这个if的作用是将自动分配的端口传给port</span> <span class="hljs-keyword">if</span> (*port == <span class="hljs-number">0</span>) <span class="hljs-comment">/* if dynamically allocating a port */</span> { <span class="hljs-type">socklen_t</span> namelen = <span class="hljs-keyword">sizeof</span>(name); <span class="hljs-comment">// 获取socket绑定的地址信息</span> <span class="hljs-keyword">if</span> (getsockname(httpd, (<span class="hljs-keyword">struct</span> sockaddr *)&name, &namelen) == <span class="hljs-number">-1</span>) error_die(<span class="hljs-string">"getsockname"</span>); *port = ntohs(name.sin_port); } <span class="hljs-comment">//监听端口</span> <span class="hljs-keyword">if</span> (listen(httpd, <span class="hljs-number">5</span>) < <span class="hljs-number">0</span>) error_die(<span class="hljs-string">"listen"</span>); <span class="hljs-keyword">return</span>(httpd);}<span class="hljs-comment">/**********************************************************************/</span><span class="hljs-comment">/* Inform the client that the requested web method has not been</span><span class="hljs-comment"> * implemented.</span><span class="hljs-comment"> * Parameter: the client socket */</span><span class="hljs-comment">/**********************************************************************/</span><span class="hljs-type">void</span> <span class="hljs-title function_">unimplemented</span><span class="hljs-params">(<span class="hljs-type">int</span> client)</span>{ <span class="hljs-type">char</span> buf[<span class="hljs-number">1024</span>]; <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"HTTP/1.0 501 guan zhu jia ran, dun dun jie chan\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, SERVER_STRING); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"Content-Type: text/html\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"<HTML><HEAD><TITLE>Method Not Implemented\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"</TITLE></HEAD>\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"<BODY><P>if you watch this page, please follow JiaRan_Diana.\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"<br/><img src='https://img2.baidu.com/it/u=2323296913,2613522307&amp;fm=253&amp;app=138&amp;size=w931&amp;n=0&amp;f=JPEG&amp;fmt=auto?sec=1658854800&amp;t=7b90c5387e83fb57a89e051eccbb7eb9'>\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>); <span class="hljs-built_in">sprintf</span>(buf, <span class="hljs-string">"</BODY></HTML>\r\n"</span>); send(client, buf, <span class="hljs-built_in">strlen</span>(buf), <span class="hljs-number">0</span>);}<span class="hljs-comment">/**********************************************************************/</span><span class="hljs-type">int</span> <span class="hljs-title function_">main</span><span class="hljs-params">(<span class="hljs-type">void</span>)</span>{ <span class="hljs-type">int</span> server_sock = <span class="hljs-number">-1</span>; <span class="hljs-comment">//服务端套接字接口</span> u_short port = <span class="hljs-number">4000</span>; <span class="hljs-comment">//端口</span> <span class="hljs-type">int</span> client_sock = <span class="hljs-number">-1</span>;<span class="hljs-comment">//已连接套接字描述符,初始化为-1(客户端)</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">sockaddr_in</span> <span class="hljs-title">client_name</span>;</span> <span class="hljs-type">socklen_t</span> client_name_len = <span class="hljs-keyword">sizeof</span>(client_name); <span class="hljs-type">pthread_t</span> newthread; <span class="hljs-comment">//调用startup()函数,建立一个监听套接字,在对应的端口建立httpd服务</span> server_sock = startup(&port); <span class="hljs-built_in">printf</span>(<span class="hljs-string">"httpd running on port %d\n"</span>, port); <span class="hljs-comment">//循环调用accept()函数来等待客户端的连接,accept()会议阻塞的方式运行</span> <span class="hljs-comment">//有客户端链接后返回到client_sock,去创建新线程处理请求</span> <span class="hljs-keyword">while</span> (<span class="hljs-number">1</span>) { client_sock = accept(server_sock, (<span class="hljs-keyword">struct</span> sockaddr *)&client_name, &client_name_len); <span class="hljs-keyword">if</span> (client_sock == <span class="hljs-number">-1</span>) error_die(<span class="hljs-string">"accept"</span>); <span class="hljs-comment">//创建新线程用accept_request()函数处理新请求,同时将客户端socket作为参数传过去</span> <span class="hljs-comment">/* accept_request(&client_sock); */</span> <span class="hljs-keyword">if</span> (pthread_create(&newthread , <span class="hljs-literal">NULL</span>, (<span class="hljs-type">void</span> *)accept_request, (<span class="hljs-type">void</span> *)(<span class="hljs-type">intptr_t</span>)client_sock) != <span class="hljs-number">0</span>) perror(<span class="hljs-string">"pthread_create"</span>); } close(server_sock); <span class="hljs-keyword">return</span>(<span class="hljs-number">0</span>);}</code></pre></div>]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>CVE-2017-17215(华为HG532远程命令执行漏洞)</title>
<link href="/article/3a44f1fa.html"/>
<url>/article/3a44f1fa.html</url>
<content type="html"><![CDATA[<p>固件和exp都已经放在这个地方了:<a href="https://gitee.com/p1piyang/backward-analysis/tree/master/">https://gitee.com/p1piyang/backward-analysis/tree/master/</a></p><p>建议先通一遍文章再动手复现,复现之前一定要保存虚拟机快照,防止出现各种奇奇怪怪的问题</p><p>首先要解决环境问题,这里只做配置说明,iot分析环境专门有一篇,请去看<code>IOT固件分析环境搭建</code> 的binwalk,qemu</p><h1 id="解压固件"><a href="#解压固件" class="headerlink" title="解压固件"></a>解压固件</h1><p>直接使用<code>binwalk -Me HG532eV100R001C02B015_upgrade_main.bin</code>命令来直接解压固件文件</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140542176.png" alt="image-20220402140542176"></p><p>解压完成后,在固件同文件夹下可以看到解压出来的文件夹</p><p>文件夹中的<code>squashfs-root</code>就是我们需要的文件系统了,如果squashfs-root中没有下图的各种文件系统,就是你的binwalk有不完整,去看<code>iot固件分析环境搭建</code></p><h1 id="配置网络"><a href="#配置网络" class="headerlink" title="配置网络"></a>配置网络</h1><p>我们要让qemu虚拟机和我们的ubuntu互通。</p><p>安装网络配置工具</p><div class="code-wrapper"><pre><code class="hljs sh">apt-get install bridge-utils uml-utilities</code></pre></div><h5 id="修改ubuntu网络配置文件-etc-network-interfaces"><a href="#修改ubuntu网络配置文件-etc-network-interfaces" class="headerlink" title="修改ubuntu网络配置文件 /etc/network/interfaces/"></a>修改ubuntu网络配置文件 <code>/etc/network/interfaces/</code></h5><p>sudo vim 你一定会把!</p><p>内容改成如下,图下提供了复制粘贴的代码(贴心人)</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140548936.png" alt="image-20220402140548936"></p><div class="code-wrapper"><pre><code class="hljs sh"><span class="hljs-comment"># interfaces(5) file used by ifup(8) and ifdown(8)</span>auto loiface lo inet loopbackauto ens33iface ens33 inet manualup ifconfig ens33 0.0.0.0 upauto br0iface br0 inet dhcpbridge_ports ens33bridge_maxwait 0</code></pre></div><h5 id="创建或修改qemu的网络接口启动文件脚本-etc-qemu-ifup"><a href="#创建或修改qemu的网络接口启动文件脚本-etc-qemu-ifup" class="headerlink" title="创建或修改qemu的网络接口启动文件脚本/etc/qemu-ifup"></a>创建或修改qemu的网络接口启动文件脚本<code>/etc/qemu-ifup</code></h5><p>如果没有这个文件直接创建就可以了,如果有的话将里边内容清空,然后写入下面脚本</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140556661.png" alt="image-20220402140556661"></p><div class="code-wrapper"><pre><code class="hljs sh"><span class="hljs-meta">#!/bin/sh</span><span class="hljs-comment"># Script to bring a network (tap) device for qemu up.</span><span class="hljs-comment"># The idea is to add the tap device to the same bridge</span><span class="hljs-comment"># as we have default routing to.</span><span class="hljs-comment"># in order to be able to find brctl</span><span class="hljs-built_in">echo</span> <span class="hljs-string">"Executing /etc/qemu-ifup"</span><span class="hljs-built_in">echo</span> <span class="hljs-string">"Bringing <span class="hljs-variable">$1</span> for bridge mode..."</span>sudo /sbin/ifconfig <span class="hljs-variable">$1</span> 0.0.0.0 promisc up<span class="hljs-built_in">echo</span> <span class="hljs-string">"Adding <span class="hljs-variable">$1</span> to br0..."</span>sudo /sbin/brctl addif br0 <span class="hljs-variable">$1</span><span class="hljs-built_in">sleep</span> 3</code></pre></div><p>然后依次执行如下操作</p><div class="code-wrapper"><pre><code class="hljs awk"><span class="hljs-comment">#启动桥接网络赋予可执行权限</span>sudo chmod a+x <span class="hljs-regexp">/etc/</span>qemu-ifup<span class="hljs-comment">#重启网络服务,使配置生效(注意这个地方配置正常之后,如果你是mac,可能会让你输入mac密码,windows我不知道😬)</span>sudo <span class="hljs-regexp">/etc/i</span>nit.d/networking restart<span class="hljs-comment">#关闭ens33,启动桥接网络br0(这里如果显示eth0不存在没关系,直接启动br0)</span>sudo ifdown eth0sudo ifup br0</code></pre></div><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140603509.png" alt="image-20220402140603509"></p><p>如图所示,当前网卡为br0</p><p>配置完之后,如果下面qemu虚拟机配置之后,仍然无法获取ip,重启ubuntu</p><h1 id="配置qemu虚拟机"><a href="#配置qemu虚拟机" class="headerlink" title="配置qemu虚拟机"></a>配置qemu虚拟机</h1><p>先去下载debian-mips-qemu镜像文件,每次固件分析要注意对应大小端序的镜像文件(还是有设备的好😭)</p><p>下载地址:<a href="https://people.debian.org/~aurel32/qemu/mips/">https://people.debian.org/~aurel32/qemu/mips/</a></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140611607.png" alt="image-20220402140611607"></p><p>我们需要红框里的两个文件,然后在文件所在地方启动qemu</p><blockquote><p>这里特别说明,最后一个参数<code>-nographic</code>带上是在终端中直接运行,不会弹出窗口运行,建议一定不要开,我这里开了之后这个窗口的返回快捷键和vmware的一模一样,就导致我只能在mac和qemu中间用,我回不去我的ubuntu了。</p></blockquote><div class="code-wrapper"><pre><code class="hljs sh">sudo qemu-system-mips -M malta -kernel vmlinux-2.6.32-5-4kc-malta -hda debian_squeeze_mips_standard.qcow2 -append <span class="hljs-string">"root=/dev/sda1 console=tty0"</span> -net nic,macaddr=00:16:3e:00:00:01 -net tap -nographic</code></pre></div><blockquote><p> 如果你的多次运行qemu,可能会出现如下错误</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140619011.png" alt="image-20220402140619011"></p><p>这是服务没有退出导致的</p><p>ps查出当前qemu进程号,kill掉就好了</p><p>ps -e | grep ‘qemu’ </p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140624914.png" alt="image-20220402140624914"></p><p>sudo kill 3307</p><p>即可</p></blockquote><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140630469.png" alt="image-20220402140630469"></p><p>启动如上图,账号密码都是root</p><p>启动后尝试,ping baidu.com 和 ubuntu</p><p>如果不通</p><div class="code-wrapper"><pre><code class="hljs sh">ifconfig -a</code></pre></div><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140637098.png" alt="image-20220402140637098"></p><p>查看网卡第一个是什么,一般都会是<code>eth1</code></p><p>然后修改<code>/etc/network/interfaces</code>,注意这里是在qemu虚拟机中修改</p><div class="code-wrapper"><pre><code class="hljs awk">nano <span class="hljs-regexp">/etc/</span>network/interfaces</code></pre></div><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140644738.png" alt="image-20220402140644738"></p><p>第一次配置红框中一般是eth0,将红框中的内容修改为你的网卡名字</p><p>保存后使用下面指令重启eth1</p><div class="code-wrapper"><pre><code class="hljs sh">ifup eth1</code></pre></div><p>再次尝试,如果还不行或者ifconfig发现eth1没有分配地址,重启ubuntu或者找原因🤔,不行就恢复快照</p><p>如果成了的话是可以用ssh远程连接qemu虚拟机的</p><div class="code-wrapper"><pre><code class="hljs sh">ssh root@虚拟机ip</code></pre></div><p>建议在ubuntu中使用ssh连接,比较方便</p><p>接下来将我们解压出来的文件系统拷贝到qemu</p><div class="code-wrapper"><pre><code class="hljs sh">scp -r ./squashfs-root root@虚拟机ip:/root/</code></pre></div><h1 id="复现"><a href="#复现" class="headerlink" title="复现"></a>复现</h1><p>通过checkpoint报告中能看到关键字为<code>ctrl</code>和<code>Deviceupgrade</code>,端口号为<code>37215</code></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/GzpgZHDk4ARtbdx.png" alt="image-20210902150556461"></p><p>使用grep来查找</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140700858.png" alt="image-20220402140700858"></p><p>两个都指向upnp这个文件,端口号指向mic这个文件</p><p>直接运行会出问题,我们切换根目录到拷贝进来的系统文件中</p><div class="code-wrapper"><pre><code class="hljs sh"><span class="hljs-built_in">chroot</span> /root/squashfs-root /bin/sh</code></pre></div><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140706608.png" alt="image-20220402140706608"></p><p>然后先后运行upnp和mic</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140714604.png" alt="image-20220402140714604"></p><p>到这个地方mic已经运行成功了,放着不用管他了</p><p>使用lsof -i:37215可以查看端口是否运行</p><p>用下面命令来查看是否启动成功</p><div class="code-wrapper"><pre><code class="hljs sh">nc -vv 192.168.150.9 37215</code></pre></div><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140722740.png" alt="image-20220402140722740"></p><p>成功了就可以跑exp了</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140729357.png" alt="image-20220402140729357"></p><p>与checkpoint不同的是,我把溢出的命令修改了(红框处,这里就是灵活使用了),蓝框处修改为qemu的ip</p><p>执行exp后 在mic界面可以看到</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140738261.png" alt="image-20220402140738261"></p><p>ls被成功执行了。</p><h1 id="原因分析"><a href="#原因分析" class="headerlink" title="原因分析"></a>原因分析</h1><p>Ida7.5可以反编译qemu🥳</p><p>通过exp能发现,命令行放在了NewStatusURL标签下,在ida中通过字符串查找</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140745136.png" alt="image-20220402140745136"></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140751334.png" alt="image-20220402140751334"></p><p>49c的位置使用快捷间p可以创建函数,来反编译</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140806829.png" alt="image-20220402140806829"></p><p>snprintf函数将可变个参数按照format格式化成字符串,然后将其复制到str中,即把v5与前面字符串拼接放到v6中,并且system执行了v6</p><p>根据exp的执行效果来推测,ATP_XML_GetChildNodeByName这个函数读取NewStatusURL标签的内容放到了v5。</p><p>伪代码不可信,尽量还是通过汇编代码分析</p><p>倒推能发现,system的参数为<code>0x42C+var_414($sp)</code></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140813521.png" alt="image-20220402140813521"></p><p><code>0x42C+var_414($sp)</code>为snprintf 的第一个参数,<code>0x42C+var_40C($sp)</code>为snprintf的第四个参数</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140822142.png" alt="image-20220402140822142"></p><p>即 <code>0x42C+var_40C($sp)</code>的内容通过函数放到了<code>0x42C+var_414($sp)</code></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140829308.png" alt="image-20220402140829308"></p><p>而<code>0x42C+var_40C($sp)</code>为ATP_XML_GetChildNodeByName的一个参数,这里应该是读取后放到了<code>0x42C+var_40C($sp)</code></p><blockquote><p>ida的锅🙃,没有办法ATP_XML_GetChildNodeByName做具体分析,但通过网上一些师傅的文章,应该大差不差了</p></blockquote><p>然后了解原理我们就可以通过闭合来实现命令运行了。</p>]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>totolink后台登录绕过</title>
<link href="/article/b3e9da69.html"/>
<url>/article/b3e9da69.html</url>
<content type="html"><![CDATA[<p>型号:<a href="http://www.totolink.cn/home/menu/newstpl.html?menu_newstpl=products&id=65">X5000R</a></p><p><a href="http://www.totolink.cn/home/menu/newstpl.html?menu_newstpl=products&id=65">AX1800 无线双频千兆路由器</a></p><p>下面有分析思路,设备模拟过程比较靠近新手,师傅们可以直接跳到后面分析过程。</p><h2 id="漏洞"><a href="#漏洞" class="headerlink" title="漏洞"></a>漏洞</h2><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140113553.png" alt="image-20220402140113553"></p><p>登陆页面构造参数,无需密码</p><p><a href="http://192.168.0.1/formLoginAuth.htm?authCode=1&userName=admin&goURL=home.html&action=login">formLoginAuth.htm?authCode=1&action=login</a></p><p>可直接绕过登陆,进入后台</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140132386.png" alt="image-20220402140132386"></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140143666.png" alt="image-20220402140143666"></p><p>产生原因在lighttpd wen服务文件from_login函数中</p><p> <img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140151857.png" alt="image-20220402140151857"></p><div class="code-wrapper"><pre><code class="hljs c++"> <span class="hljs-keyword">if</span> (iVar2 == <span class="hljs-number">0</span>) { iVar1 = <span class="hljs-built_in">strcmp</span>((<span class="hljs-type">char</span> *)&sa58,<span class="hljs-string">"ie8"</span>); <span class="hljs-keyword">if</span> (iVar1 == <span class="hljs-number">0</span>) { pcVar1 = <span class="hljs-string">"/login_ie.html"</span>; } <span class="hljs-keyword">else</span> { iVar1 = <span class="hljs-built_in">atoi</span>((<span class="hljs-type">char</span> *)&sa58); <span class="hljs-keyword">if</span> (iVar1 == <span class="hljs-number">1</span>) { pcVar2 = <span class="hljs-string">"/login.html"</span>; pcVar1 = <span class="hljs-string">"http://%s%s%s"</span>; pcVar3 = <span class="hljs-string">"/phone"</span>;LAB_409114: <span class="hljs-built_in">sprintf</span>(param_2,pcVar1,acStack1860,pcVar3,pcVar2); <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>; } pcVar1 = <span class="hljs-string">"/login.html"</span>; } <span class="hljs-built_in">sprintf</span>(param_2,<span class="hljs-string">"http://%s%s"</span>,acStack1860,pcVar1); <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>; }</code></pre></div><p>上面代码是登陆检查,当iVar2=1的时候,直接跳过检查,不需要登陆。</p><p>iVar2的值是autoCode参数的值。</p><p>所以构造autoCode=1即可绕过。</p><hr><h2 id="模拟"><a href="#模拟" class="headerlink" title="模拟"></a>模拟</h2><p>下面是详细分析思路。</p><p>今天偶然发现这款非常小众的路由器,至于多小众,我分析这款官方月销15台。</p><p>我分析的这款是 AX1800,官方可以直接下载固件。</p><p>这款固件超级适合新手第一次分析使用。</p><p>binwalk分析</p><div class="code-wrapper"><pre><code class="hljs bash">binwalk TOTOLINK_C8343R-1C_X5000R_IP04433_MT7621A_SPI_16M256M_V9.1.0u.6118_B20201102_ALL.web</code></pre></div><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140204590.png" alt="image-20220402140204590"></p><p>squashfs文件系统,uImage,LZMA压缩文件中应该也是个比较大的内容,直接使用-Me参数递归提取。</p><div class="code-wrapper"><pre><code class="hljs bash">binwalk -Me TOTOLINK_C8343R-1C_X5000R_IP04433_MT7621A_SPI_16M256M_V9.1.0u.6118_B20201102_ALL.web</code></pre></div><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140212668.png" alt="image-20220402140212668"></p><p>里面有标准的文件系统</p><p>查看架构</p><div class="code-wrapper"><pre><code class="hljs bash">binwalk ./bin/busybox</code></pre></div><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140219607.png" alt="image-20220402140219607"></p><p>mips小端序,查看其文件系统瞅瞅有没有什么东西。</p><p>有个工具叫firmwalker,可以自动分析文件系统,提取重要文件,我个人觉得不是特别好用。</p><p>我比较推荐使用vscode来做分析。</p><p>下面是要关注的一些地方</p><div class="code-wrapper"><pre><code class="hljs bash">etc/ <span class="hljs-comment">#这里会存放系统启动文件如openwrt的rcS文件</span>sbin/ <span class="hljs-comment">#这里一般会存放厂商制作的功能性文件和提供web服务的文件</span>www/ <span class="hljs-comment">#这里会存放一些web静态页面和后台服务文件文件</span></code></pre></div><p>其他地方也尽量看一下,经验多了就容易清楚哪些文件是做什么的了,没经验就慢慢来。</p><p>这里发现了这几个文件:</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140228610.png" alt="image-20220402140228610"></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140234876.png" alt="image-20220402140234876"></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140239433.png" alt="image-20220402140239433"></p><p>可以看到他使用了lighttpd 的web服务文件,</p><p>一般固件大概会有这几个轻量级httpd文件:lighttpd,httpd,uhppd。</p><p> 其他的还有很多。</p><p>尝试使用qemu-user模拟http服务。</p><div class="code-wrapper"><pre><code class="hljs bash"><span class="hljs-built_in">cp</span> (<span class="hljs-built_in">which</span> qemu-mipsel-static) ./sudo <span class="hljs-built_in">chroot</span> . ./qemu-mipsel-static ./usr/sbin/lighttpd</code></pre></div><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140244941.png" alt="image-20220402140244941"></p><p>这里的报错是需要用-f参数指定配置文件,上面已经发现了lighttpd.conf文件。</p><div class="code-wrapper"><pre><code class="hljs bash">sudo <span class="hljs-built_in">chroot</span> . ./qemu-mipsel-static ./usr/sbin/lighttpd -f ./lighttp/lighttpd.conf</code></pre></div><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140250832.png" alt="image-20220402140250832"></p><p>没有这个文件,这里我们先去把这个路径改一下,在lighttpd.conf中</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140256520.png" alt="image-20220402140256520"></p><p>把它改到固件的系统文件中<code>./var/run/lighttpd.pid</code>,并且去创建这个文件。</p><p>运行</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140301896.png" alt="image-20220402140301896"></p><p>这里虽然正常启动,但是如果不挂载文件夹,还是挺多问题的,所以我更倾向使用系统模式。</p><p>所以下面的分析都是在系统模式下的。</p><p>这里系统模式不做赘述,我写了个脚本,可以很方便启动。</p><p>核心文件比较大,大家按文件自行下载</p><p><a href="https://people.debian.org/~aurel32/qemu/mips/">https://people.debian.org/~aurel32/qemu/mips/</a></p><p>我把脚本放链接放这里</p><p><a href="https://gitee.com/p1piyang/backward-analysis/tree/master/">https://gitee.com/p1piyang/backward-analysis/tree/master/</a></p><p>qemu启动</p><div class="code-wrapper"><pre><code class="hljs bash">sudo ./start-mipsel.sh</code></pre></div><p>sudo 启动</p><div class="code-wrapper"><pre><code class="hljs bash">ifconfig eth0 192.168.5.12 up <span class="hljs-comment">#qemu中设置ip,qemu里边</span></code></pre></div><p>将文件系统上传</p><div class="code-wrapper"><pre><code class="hljs bash">scp -r squashfs-root/ [email protected]:/root/ <span class="hljs-comment">#在主机</span></code></pre></div><p>挂载</p><div class="code-wrapper"><pre><code class="hljs bash"><span class="hljs-built_in">chroot</span> ./squashfs-root/ /bin/sh</code></pre></div><p>启动</p><div class="code-wrapper"><pre><code class="hljs bash">./user/sbin/lighttpd -f ./lighttp/lighttpd.conf</code></pre></div><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140309147.png" alt="image-20220402140309147"></p><h2 id="分析"><a href="#分析" class="headerlink" title="分析"></a>分析</h2><p>刚开始是想直接去分析lighttpd的。随手登陆了一下,看了下包。</p><blockquote><p> 我个人浅薄的经验,不要单纯去无目的的分析某个应用,我之前犯过这种错误,太容易对着一个程序漫无目的的乱逛,希望你没有这种情况。</p></blockquote><p>这里明显可以看到调用了cgi文件,之前看文件的时候看到了这个东西的。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140319324.png" alt="image-20220402140319324"></p><p>可以去分析下这个文件。</p><div class="code-wrapper"><pre><code class="hljs sql">ghidra <span class="hljs-keyword">open</span>!!!Link 死大头!!!<span class="hljs-keyword">search</span> "action"!!!</code></pre></div><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140324232.png" alt="image-20220402140324232"></p><p>action=login,交叉引用,看一下。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140332012.png" alt="image-20220402140332012"></p><p>说实话,ghidra的这个伪代码看着老奇怪了,这里是判断了登陆还是升级。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140340535.png" alt="image-20220402140340535"></p><p>if下面,这里判断flag=1,最后的逻辑是将字符串格式化到<code>acStack4456</code>中</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140405176.png" alt="image-20220402140405176"></p><p>再往下这个地方我刚开始比较懵了,因为<code>websGetVar程序查找表变量var</code>,相当于获取参数。所以这里并没有往下看,而是换了个思路点。</p><p>这里知道了他是对登陆做了个判断。</p><p>去查找登陆的请求参数</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140416345.png" alt="image-20220402140416345"></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140422127.png" alt="image-20220402140422127"></p><p>发现了这么个地方。</p><p>根据登陆的包。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140429266.png" alt="image-20220402140429266"></p><p>发现他返回了一串地址。并且主动访问了这串地址。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140435525.png" alt="image-20220402140435525"></p><p>所以这个地方是判断密码的地方。本来想试试正确密码,来分析下,结果密码怎么都不对。</p><p>这里解释下,因为我没有设备,是直接在官网下载的固件,所以这个密码怎么都不对,我怀疑是固件模拟的问题,就没有往下追究。</p><p>他主动访问了formloginAuth.htm,在www/文件夹下并没有这个文件,所以去找下lighttpd文件分析下</p><div class="code-wrapper"><pre><code class="hljs sql">ghidra <span class="hljs-keyword">open</span>!!!Link 死大头!!!<span class="hljs-keyword">search</span> "formLoginAuth"!!!</code></pre></div><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140442157.png" alt="image-20220402140442157"></p><p>跟进from_Login函数</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140458964.png" alt="image-20220402140458964"></p><p>这里就发现了参数处理</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140507794.png" alt="image-20220402140507794"></p><p>判断几个参数做了什么,userName是空的先不看,goURL是某个html文件,盲猜他是的从哪来的,action是要做什么。</p><p>所以现在要看一下authCode</p><p>如果authCode不等于0,iVar2就等于整形的authCode的值。</p><p>往下分析。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140512311.png" alt="image-20220402140512311"></p><p>这里改成1之后直接,跳过了这个判断。</p><p>但是只吧这个改为1之后还是返回到登陆界面。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140520920.png" alt="image-20220402140520920"></p><p>这里pcVar2=1,导致跳过了设置pcVar2 = home.html</p><p>所以我猜测goUrl参数不是从哪来,而是从哪去。</p><p>最后发现果然是哦。</p><p>其实在ghidra反编译的时候,好多地方不太习惯,很多地方靠函数名和字符串硬猜。</p><p>慢慢来吧。</p>]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>路由器固件解密思路</title>
<link href="/article/876237c8.html"/>
<url>/article/876237c8.html</url>
<content type="html"><![CDATA[<p>学习思路来源于zdi:<code>https://www.zerodayinitiative.com/blog/2020/2/6/mindshare-dealing-with-encrypted-router-firmware</code></p><p>关于如何判断是否加密在另一篇文章有提到: <code>https://p1yang.github.io/2022/04/02/iot/iot学习感悟/</code></p><p>一般来说固件加密有三种情况:</p><ol><li>初始版本未加密,后续某个版本加密了 在加密与初始版本中间某个版本附带了解密程序</li></ol><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220427111553846.png" alt="image-20220427111553846"></p><p> 获取中间版本,从中分析解密程序。</p><ol start="2"><li>老版有加密,后续更换加密方式,中间发布未加密的过渡版本固件</li></ol><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220427113725651.png" alt="image-20220427113725651"></p><p> 与1类似,也是同样获取带有解密程序的过渡版本固件分析提取解密程序</p><ol start="3"><li>老版有加密,后续更换加密方式,中间更换了新的未加密的解密程序</li></ol><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220427114528196.png" alt="image-20220427114528196"></p><p> 如果清楚早期加密方式,或者拥有早期解密程序,可以去分析更换解密程序的中间版本,来获取解密程序。</p><p> 如果没有早期相关解密信息,则无法使用上面方式,更多是购买设备,从硬件直接提取未加密的固件。</p><p> 理论上,可以使用二进制对比分析工具,来分析尝试提取复原解密程序。</p><p>这是选用了经典的Dlink-DIR882的固件进行分析:</p><p>ftp:<a href="ftp://ftp2.dlink.com/PRODUCTS/DIR-882/REVA/">ftp://ftp2.dlink.com/PRODUCTS/DIR-882/REVA/</a></p><p>从固件时间顺序往早期查验</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220427115925211.png" alt="image-20220427115925211"></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220427120035013.png" alt="image-20220427120035013"></p><p>发现<code>DIR882A1_FW104B02_Middle_FW_Unencrypt.bin</code>就是我们所说的过渡版本。</p><p>提取,分析,我们要通过他来查找解密程序。</p><p>或者复现根据升级路径来查找。</p><p>这里比较幸运通过关键字查到在bin下的imgdecrypt,但我们不能确定他一定是正确的解密程序</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220427143219538.png" alt="image-20220427143219538"></p><p>我们尝试执行他。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220427151046949.png" alt="image-20220427151046949"></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220427151221942.png" alt="image-20220427151221942"></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220427151356109.png" alt="image-20220427151356109"></p><p>跟上面对比,正确能够被识别出文件。</p><p>尝试将其他固件也都测试下</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220427152259592.png" alt="image-20220427152259592"></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220427152314636.png" alt="image-20220427152314636"></p><p>上面是命名比较规范的一种,有些命名不规范可能需要去根据前端升级去寻找相应的功能。</p>]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>iot学习感悟</title>
<link href="/article/41f88cb3.html"/>
<url>/article/41f88cb3.html</url>
<content type="html"><![CDATA[<h1 id="关于加密"><a href="#关于加密" class="headerlink" title="关于加密"></a>关于加密</h1><p>前期接触iot我们遇到固件基本都是binwalk一把梭,但有时候会遇到固件信息混乱,或者分析出来一堆zlma的文件,没有发现有rtos或者文件系统的标志。</p><p>这时候会考虑到是否加密,上网查会发现有用 binwalk 的 -E 参数来判断。</p><p>那么这个判断的原理是啥?</p><p>原理是信息熵。</p><blockquote><p> 熵:泛指某些物质系统状态的一种量度,某些物质系统状态可能出现的程度。</p></blockquote><p>初高中应该都学过,熵值越大,说明系统越混乱。</p><blockquote><p> 信息熵:1948年C.E.Shannon(香农)从热力学中借用过来提出的概念,解决了对信息的量化度量问题</p></blockquote><p>信息中,重复的内容越多,系统越稳定,能获得的信息越多。</p><blockquote><p>对于没有加密的二进制文件来说,某些指令出现的频率通常很高(如序言、nop序列等),并且数据结构几乎没有随机性。重复概率很高</p></blockquote><p>所以,对于未加密的数据来说熵值一般会比较低。</p><blockquote><p>对于经过加密的文件来说,都会想尽办法隐藏自己的信息,而导致很少有重复的内容,也就导致重复概率低</p></blockquote><p>所以,加密的熵值一般都会高。</p><p>上面就是通过信息熵来判断是否加密,binwalk使用相关算法来整理信息熵</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140534018.png" alt="image-20220402140534018"></p><h1 id="关于web服务"><a href="#关于web服务" class="headerlink" title="关于web服务"></a>关于web服务</h1><p>嵌入式的web服务通常是cgi+http 或 lua+http</p><p>cgi是叫公共网关接口,是Web 服务器运行时外部程序的规范,按<em>CGI</em> 编写的程序可以扩展服务器功能</p><p><em>Lua</em> 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。</p><p>常见的嵌入式设备使用的web服务多为以下几款</p><h2 id="boa"><a href="#boa" class="headerlink" title="boa"></a>boa</h2><p>单一任务型的http服务器,只会对CGI请求进行<code>fork</code>进程,没有访问控制功能,身份认证都是厂商后边开发的。</p><p>通过<code>translate_uri</code>函数解析请求路径I判断是否为CGI请求,调用<code>init_cgi</code>来<code>execve</code>执行相关CGI程序</p><p><code>translate_uri</code>函数中的<code>init_script_alias</code>函数,负责解析<code>ScriptAlias</code>请求,设置请求cgi类型,查看文件是否存在以及具有相关权限</p><p>通过<code>ScriptAlias</code>在<code>boa.conf</code>配置文件中,该指令设置CGI执行的真实目录</p><blockquote><p>不止是boa,nginx的设置中也存在alias,小米路由器就曾因为这个设置导致路径穿越</p></blockquote><h2 id="uhttpd"><a href="#uhttpd" class="headerlink" title="uhttpd"></a>uhttpd</h2><p>openwrt的默认http服务器,主要是为了和LucI Web接口方便OpenWrt设备管理。</p><p>支持与cgi,lua,UBUS来完成请求。</p><p>uhttpd使用LuCI框架编写lua处理脚本,安全审计偏向于Web安全中的代码审计。</p><p>但也有一些存放的lua脚本是编译过的,需要逆向。</p><p>uhttp下<code>dispatch_find</code>函数根据请求的url找到合适的<code>dispatch_handler</code>。</p><p>请求的url通过<code>check_cgi_path</code>函数校验,则会调用<code>cgi_handle_request</code>函数回调<code>cgi_main</code>函数<code>execl</code>执行对应的CGI程序</p><p>最终调用的<code>/www/cgi-bin/luci</code>即Luci,luci是MVC设计思想的web后端框架。</p><p>简单了解下,后面一款小米路由器分析思路会详细介绍</p><h2 id="Goahead"><a href="#Goahead" class="headerlink" title="Goahead"></a>Goahead</h2><p>在<code>route.txt</code>定义的路由规则,根据匹配的URI来执行不同的handler:有action handler直接在GoAhead进程中执行C函数,CGI handler执行新的CGI程序,也有默认的file handler处理文件请求,还可以自定义新的handler</p><p>详细请看官方文档:<a href="https://www.embedthis.com/goahead/doc/">https://www.embedthis.com/goahead/doc/</a></p><p>调用<code>websUrlHandlerRequest</code>函数找到匹配URL前缀的处理函数,可以借助<code>websFormDefine</code>函数定义与<code>formName</code>相关联的C处理函数</p><p>由上面几个可以看出来,都是通过URL来选择执行CGI/lua或是内部程序</p><p>并且根据<code>PATH_INFO</code>选择执行程序内最终的handler函数。</p><p>这里属于个人复述,这个文章比较详细:<a href="https://github.com/Larryxi/Larryxi.github.io/blob/master/_posts/2020-02-03-iot-web-server-cgi-handler-analysis.md">https://github.com/Larryxi/Larryxi.github.io/blob/master/_posts/2020-02-03-iot-web-server-cgi-handler-analysis.md</a></p><h1 id="分析的一些思路"><a href="#分析的一些思路" class="headerlink" title="分析的一些思路"></a>分析的一些思路</h1><p>分析的话根据上面的东西来看</p><p>一定要有个设备,或者去模拟这些设备。</p><p>保证正常的web访问,方便查看功能调用的url/接口。</p><blockquote><p>一定不要去公网站直接用人家的设备,要做个守法的好孩子!!!</p></blockquote><p>根据上面的知识来获取相关功能的具体实现位置。</p><p>然后分析危险函数,以及是否可控。</p><p>或者</p><p>从危险函数向外分析功能点。</p>]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>tenda路由器的漏洞发现</title>
<link href="/article/44df6587.html"/>
<url>/article/44df6587.html</url>
<content type="html"><![CDATA[<p>分析这款是tendaA1206,固件是比较早的未加密的那个。</p><p>都是些个人学习过程中的思考与知识,整理下来。</p><p>固件在这:<code>https://p1yang.github.io/2022/04/22/iot/tenda路由器的漏洞发现/</code></p><h1 id="前期准备"><a href="#前期准备" class="headerlink" title="前期准备"></a>前期准备</h1><p>都是些老生常谈的东西可以跳过。</p><p>这里使用的qemu-user,方便</p><p>至于分析的文件在下面思路中会聊到,这里环境模拟启动的是/bin/httpd 文件</p><p>复现环境是qemu+ghidra(反编译伪代码,我个人比较习惯ghidra的伪代码)+ida7.5(动态调试)</p><p>binwalk解包,文件格式,qemu-user模式启动等这些就不赘述,主要说几个环境模拟时的几个小问题。</p><h2 id="问题1"><a href="#问题1" class="headerlink" title="问题1"></a>问题1</h2><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422093901642.png" alt="image-20220422093901642"></p><p>第一次运行时爆出这个错误停止。string大法发现在main中</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422094037256.png" alt="image-20220422094037256"></p><p><code>apmib_init</code>函数从flash中读取mib值到RAM中,像这种模拟是办不到的东西,直接patch代码或更改寄存器值来绕过(尝试了下没办法直接patch代码,可以试试patch机器码,比较麻烦,我就直接改寄存器了)</p><p>在mips的判断是bne,btgz等,将断点下在他们上,他们通常依靠v0寄存器的值来做判断。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422094858896.png" alt="image-20220422094858896"></p><p>此时v0值为0,改为1跳过</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422095038420.png" alt="image-20220422095038420"></p><h2 id="问题2"><a href="#问题2" class="headerlink" title="问题2"></a>问题2</h2><p>这里陷入个死循环,问题点在</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422101918935.png" alt="image-20220422101918935"></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422102003495.png" alt="image-20220422102003495"></p><p>也尝试更改寄存器v0的值成功绕过。</p><h2 id="问题3"><a href="#问题3" class="headerlink" title="问题3"></a>问题3</h2><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422095242595.png" alt="image-20220422095242595"></p><p>继续string大法</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422095310053.png" alt="image-20220422095310053"></p><p>抱歉这里我并没有查到这个函数的是干什么的,有清楚的请告诉我,提前感谢。</p><p>不影响,改寄存器大法。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422095958809.png" alt="image-20220422095958809"></p><h2 id="问题4"><a href="#问题4" class="headerlink" title="问题4"></a>问题4</h2><p>上面没问题之后发现ip开在<code>255.255.255.255</code>上。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422102645100.png" alt="image-20220422102645100"></p><p>string大法搜 listen ip</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422103034994.png" alt="image-20220422103034994"></p><p><code>inet_ntoa</code>函数的意思是,功能是将网络地址转换成“.”点隔的字符串格式。</p><p>所以跟sockaddr.sin_port有关,查看引用</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422103359077.png" alt="image-20220422103359077"></p><p><code>inte_addr</code> 功能是将一个点分十进制的IP转换成一个长整型数(u_long类型)等同于<em>inet_addr</em>()。</p><p>与host有关,再向前查看</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422103859404.png" alt="image-20220422103859404"></p><p>其参数为全局变量 g_lan_ip。设置个lanip</p><blockquote><p>sudo tunctl -t br0 -u ‘用户名’</p><p>sudo ifconfig br0 192.168.5.1/24</p></blockquote><p> ps eth1就是第二块网卡第一块通常是eth<em>0</em> <em>tap</em>是虚拟网络接口 <em>br</em>是网桥</p><p>这个设置完之后问题2直接解决了。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422110341615.png" alt="image-20220422110341615"></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422110418896.png" alt="image-20220422110418896"></p><h1 id="分析思路"><a href="#分析思路" class="headerlink" title="分析思路"></a>分析思路</h1><p>分析其使用的web服务器,常见的嵌入式有以下几种:httpd,uhttpd,gohead,lighttpd,boa</p><p>还有其他的,我没咋见过,就不写了,用到的话自行查阅(懒!)</p><p>我分析这款使用的是httpd,在bin目录下,一般服务器文件都在一下几个目录,不排除其他目录</p><div class="code-wrapper"><pre><code class="hljs awk"><span class="hljs-regexp">/user/</span>bin/<span class="hljs-regexp">/user/</span>sbin/<span class="hljs-regexp">/bin/</span></code></pre></div><p>在逆向分析httpd时,尽量关注一些自定义功能代码,main下调用的initwebs函数中,配置了前端访问方式</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422112301584.png" alt="image-20220422112301584"></p><p>可以看到默认页面main,</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422112355613.png" alt="image-20220422112355613"></p><p><code>websSetPassword</code>设置访问口令,不多说各位调试的时候可以关注一下。</p><p><code>websUrlHandlerDefine</code>需要关注,这个函数的意思是什么样的url交给谁处理。</p><p>上面说了<code>尽量关注一些自定义功能代码</code></p><p>这里的自定义功能代码就在<code>formDefineTendDa</code>中</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422113423088.png" alt="image-20220422113423088"></p><p>上面这些都是通过<code>goform</code>来处理的,所以其访问形式为 <a href="http://127.0.0.1/goform/TendaGetLongString%E8%BF%99%E6%A0%B7%E7%9A%84">http://127.0.0.1:80/goform/TendaGetLongString这样的</a></p><p>哪个路径就交由哪个函数来处理。</p><p>下面分析可以由两方面展开:</p><p>分析各个功能点</p><blockquote><p> 简单来说就是将所有接口的代码过一遍,去分析参数从哪里来,有没有经过什么危险函数</p></blockquote><p>这种的话效率比较低,我个人推荐第二种</p><p>通过危险函数来查找可利用点,利用逆向分析工具的交叉编译功能查找</p><p>这里放一张危险函数表</p><p>dosystemcmd</p><p>system</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/0B814D68-9F2F-437C-A067-BB97942160E8.png">根据上面的函数表来将危险函数过一下</p><p>下面是之前分析到的两个问题的思路,住这里不涉及exp,poc等脚本的编写,还是以思路为主。</p><h2 id="命令执行"><a href="#命令执行" class="headerlink" title="命令执行"></a>命令执行</h2><p>过一遍dosystemcmd函数</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422141922087.png" alt="image-20220422141922087"></p><p>可以看到有145次调用,感觉有漏洞的几率还是挺大的</p><p>注意点,尽量找form这类的函数,即上面说的自定义功能,有前后端交互</p><p>且危险函数的参数来自于前端参数</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220422142703774.png" alt="image-20220422142703774"></p><p><code>websGetVar</code>就是从wp中获取其第二个参数对应的值,如果没有该参数,值默认为第三个参数。</p><p>上面可以看到这里pcVar1未作任何处理直接拼接到参数中。</p><p>这里就产生了命令执行,不多做赘述,各位有兴趣可自行复现。</p><h2 id="溢出"><a href="#溢出" class="headerlink" title="溢出"></a>溢出</h2><p>溢出是在strpintf函数的调用中发现的。</p><p>goform/NatStaticSetting路径访问到fromNatStaticSetting函数</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/wpsnHFtW8.jpg" alt="img"> </p><p>sprintf函数将page的参数给拼接到字符串中,未做长度校验,导致溢出</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/wpsOGISIR.jpg" alt="img"> </p><p>复现过程:</p><p>断点到fromNatStaticSetting函数入口</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/wps0paJou.jpg" alt="img"> </p><p>将调用fromNatStaticSetting函数的返回地址放入0x407FFAE4 处</p><p>向下执行到第三个websGetVar函数获取page参数,然后向下执行sprintf函数,将page参数的内容拼接到gotopage内,由代码可知长度为256</p><p>参数初始化完毕后发现gotopage位置为0x407FF9E0</p><p>这里我们传入page参数为:</p><div class="code-wrapper"><pre><code class="hljs abnf"><span class="hljs-attribute">page</span><span class="hljs-operator">=</span>aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaacAAAA</code></pre></div><p>执行完后</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/wpsi5rSOK.jpg" alt="img"> </p><p>返回地址0x407FFAE4已经被AAAA覆盖。</p><p>上面是一些思路之类的东西,第一个命令执行晚了几天。</p>]]></content>
<categories>
<category>iot</category>
</categories>
</entry>
<entry>
<title>关于我</title>
<link href="/article/9ff79b23.html"/>
<url>/article/9ff79b23.html</url>
<content type="html"><![CDATA[<p>我</p><p>p1yang</p><p>24(年轻人,不讲武德)</p><p>rewirte战队成员(感谢我的几位好哥哥带我)</p><p>万年单身狗(有喜爱狗狗的小姐姐可以考虑下)(bushi)</p><p>2023成功追女生失败,还是一个单身狗。</p><p>一个网络安全爱好者(师傅们带带我)</p><p>菜鸡(这是真的)</p><p>二进制玩家(这玩意好难,好难,好难!!!)</p><p>android开发专业废物(我ui画的贼溜)</p><p>复制诗歌爱好者(致橡树我真的太喜欢了!!!)</p><p>初音厨(即使离婚了我也爱她)</p><p>”日常“番爱好者(没有未来的未来不是我想要的未来)</p><p>正在学画本子的渣渣(哎嘿嘿)</p><p>英雄联盟万年黑铁(我闪现撞墙贼溜)</p><p>爹一只会窝在后排打狙(十倍镜都打不到人)</p><p>csgo皮肤收藏家(就是买不起而已,rush B gogogo!)</p><p>这个博客算是第二次迁移了吧,之前在云服务器上的也停了,文章也没来得及保存。</p><p>这里就算一个新的开始吧。</p><p>最后留个联系方式吧,师傅们有想要交流的技术或者不嫌弃我菜,一块耍爹1或者本人博文有问题的地方联系qq提醒我修改吧。</p><p>qq:397712823</p>]]></content>
<categories>
<category>杂七杂八的唠叨话</category>
</categories>
</entry>
<entry>
<title>Windows ShellCode提取加载与免杀</title>
<link href="/article/570c6a7.html"/>
<url>/article/570c6a7.html</url>
<content type="html"><![CDATA[<p>这篇文章仅讲windows下的,linux下比较简单,之后可能会写</p><p>shellcode是一段用于利用软件漏洞而执行的代码</p><h1 id="编写"><a href="#编写" class="headerlink" title="编写"></a>编写</h1><p>首先说明,shellcode编写可以用c也可以直接用汇编来写,但难度不在一个层级,我们选择c》</p><p>vs我用的是vs2013,本来用的2008,但是找不到汇编窗口</p><p>下面是windows shellcode编写的步骤</p><blockquote><p>获取kernel32.dll 基地址; </p><p>定位 GetProcAddress函数的地址; </p><p>使用GetProcAddress确定 LoadLibrary函数的地址; </p><p>然后使用 LoadLibrary加载DLL文件(例如user32.dll); </p><p>使用 GetProcAddress查找某个函数的地址(例如MessageBox); </p><p>指定函数参数; </p><p>调用函数。</p></blockquote><p>首先要注意shellcode的<code>地址无关</code>原则</p><div class="code-wrapper"><pre><code class="hljs c++"><span class="hljs-type">char</span>* arr = <span class="hljs-string">"test"</span>;</code></pre></div><p>我们看到这么写的话 test存放在一个固定地址,而不同windows下的内存地址是不同的,所以我们不能将地址写死</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141753290.png" alt="image-20220402141753290"></p><div class="code-wrapper"><pre><code class="hljs c++"><span class="hljs-type">char</span> cmd[] = { <span class="hljs-string">'c'</span>,<span class="hljs-string">'a'</span>,<span class="hljs-string">'l'</span>,<span class="hljs-string">'c'</span>,<span class="hljs-string">'\x00'</span>};</code></pre></div><p>但上面这种写法就不会有固定地址,但这样写需要用<code>\x00</code>来截断</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141804620.png" alt="image-20220402141804620"></p><p>现在地址无关解决,下一步是函数调用,我们需要kernel32.dll 基地址,但是由于ASLR导致dll可以加载到不同的内存位置,需要动态定位</p><p>PEB结构位于固定内存位置,所以我们可以通过PEB来获取。</p><blockquote><p>读取PEB结构 </p><p>跳转到0xC偏移处读取Ldr指针 </p><p>跳转到0x14偏移处读取 InMemoryOrderModuleList字段</p></blockquote><p>如果你不太懂上面三步,尽量多思考一下下面的内容</p><blockquote><p>进程:是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,可以简单的理解为,计算机中每运行的一个软件都是一个进程。</p><p>PEB:是一个位于所有进程内存中固定位置的结构体。此结构体包含关于进程的有用信息,如可执行文件加载到内存的位置,模块列表(DLL),指示进程是否被调试的标志,还有许多其他的信息。</p></blockquote><div class="code-wrapper"><pre><code class="hljs c++"><span class="hljs-keyword">typedef</span> <span class="hljs-keyword">struct</span> <span class="hljs-title class_">_PEB</span> { BYTE Reserved1[<span class="hljs-number">2</span>]; BYTE BeingDebugged; BYTE Reserved2[<span class="hljs-number">1</span>]; PVOID Reserved3[<span class="hljs-number">2</span>]; PPEB_LDR_DATA Ldr; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; BYTE Reserved4[<span class="hljs-number">104</span>]; PVOID Reserved5[<span class="hljs-number">52</span>]; PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; BYTE Reserved6[<span class="hljs-number">128</span>]; PVOID Reserved7[<span class="hljs-number">1</span>]; ULONG SessionId;} PEB, *PPEB;</code></pre></div><p>上面是微软关于PEB结构体的官方文档,</p><blockquote><p>上面内容的一些概念</p><p>BYTE表示1个字节</p><p>PVOID表示1个指针(或1个内存地址,ps:一定要弄明白指针这东西,很重要)在0x86中一个地址占四个字节</p><p>PPEB_LDR_DATA是1个指针,指向自定义结构体PEB_LDR_DATAPEB_LDR_DATA</p><p>BeingDebugged标志是1个字节</p><p>Reserved1[2]是两个BYTE的数组,占两个字节</p><p>Reserved3[2]是两个PVOID指针的数组,占八个字节</p></blockquote><p>我们重点关注下PEB_LDR_DATA(跳转到0xC偏移处读取Ldr指针 )</p><p>跳转偏移计算:2 + 1 + 1 + 8 = 12 = 0xC</p><div class="code-wrapper"><pre><code class="hljs c++"><span class="hljs-keyword">typedef</span> <span class="hljs-keyword">struct</span> <span class="hljs-title class_">_PEB_LDR_DATA</span> { BYTE Reserved1[<span class="hljs-number">8</span>]; PVOID Reserved2[<span class="hljs-number">3</span>]; LIST_ENTRY InMemoryOrderModuleList;} PEB_LDR_DATA, *PPEB_LDR_DATA;</code></pre></div><p>关注LIST_ENTRY InMemoryOrderModuleList(跳转到0x14偏移处读取 InMemoryOrderModuleList字段)</p><p>跳转偏移计算:8 + 12 = 20 = 0x14</p><div class="code-wrapper"><pre><code class="hljs c++"><span class="hljs-keyword">typedef</span> <span class="hljs-keyword">struct</span> <span class="hljs-title class_">_LIST_ENTRY</span> { <span class="hljs-keyword">struct</span> <span class="hljs-title class_">_LIST_ENTRY</span> *Flink; <span class="hljs-keyword">struct</span> <span class="hljs-title class_">_LIST_ENTRY</span> *Blink;} LIST_ENTRY, *PLIST_ENTRY;</code></pre></div><p>LIST_ENTRY结构是一个简单的双向链表,包含指向下一个元素(Flink)的指针和指向上一个元素的指针(Blink)</p><p>InMemoryOrderModuleList字段是一个指针,指向LDR_DATA_TABLE_ENTRY 结构体上的LIST_ENTRY字段。但是它不是指向</p><p>LDR_DATA_TABLE_ENTRY 起始位置的指针,而是指向这个结构的InMemoryOrderLinks字段。</p><p>上面操作完到了内存首个<code>模块</code>的InMemoryOrderLinks元素,这个<code>模块</code>是一个可执行文件(.exe),我们需要去遍历加载到内存的dll文件。</p><p>具体通过InMemoryOrderModuleList.Flink来访问第二个已加载的模块,通过循环操作就可以遍历所有已加载的模块</p><blockquote><p>calc.exe </p><p>ntdll.dll </p><p>kernel32.dll </p></blockquote><p>当我们通过遍历得到kernel32.dll后就可以完成下面操作了</p><blockquote><p>获取kernel32.dll 基地址; </p><p>定位 GetProcAddress函数的地址; </p><p>使用GetProcAddress确定 LoadLibrary函数的地址; </p><p>然后使用 LoadLibrary加载DLL文件(例如user32.dll); </p><p>使用 GetProcAddress查找某个函数的地址(例如MessageBox); </p><p>指定函数参数; </p><p>调用函数。</p></blockquote><p>这边有个代码模版,如果你实在不会写可以参考这个模版来理解上述操作</p><div class="code-wrapper"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span><span class="hljs-string"><Windows.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span><span class="hljs-string"><winnt.h></span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span><span class="hljs-string"><winternl.h></span></span><span class="hljs-function">DWORD <span class="hljs-title">getHash</span><span class="hljs-params">(<span class="hljs-type">char</span>* str)</span> </span>{DWORD h = <span class="hljs-number">0</span>;<span class="hljs-keyword">while</span> (*str) {h = (h >> <span class="hljs-number">13</span>) | (h << (<span class="hljs-number">32</span> - <span class="hljs-number">13</span>));h += *str >= <span class="hljs-string">'a'</span> ? *str - <span class="hljs-number">32</span> : *str;str++;}<span class="hljs-keyword">return</span> h;}<span class="hljs-function">DWORD <span class="hljs-title">getunicodeHash</span><span class="hljs-params">(<span class="hljs-type">wchar_t</span>* str)</span> </span>{DWORD h = <span class="hljs-number">0</span>;PWORD ptr = (PWORD)str;<span class="hljs-keyword">while</span> (*ptr) {h = (h >> <span class="hljs-number">13</span>) | (h << (<span class="hljs-number">32</span> - <span class="hljs-number">13</span>));h += (BYTE)(*ptr) >= <span class="hljs-string">'a'</span> ? (BYTE)(*ptr) - <span class="hljs-number">32</span> : (BYTE)(*ptr);ptr++;}<span class="hljs-keyword">return</span> h;}<span class="hljs-function">PVOID <span class="hljs-title">getWinExec</span><span class="hljs-params">()</span> </span>{<span class="hljs-type">char</span> dllname[] = { <span class="hljs-string">'K'</span>,<span class="hljs-string">'E'</span>,<span class="hljs-string">'R'</span>,<span class="hljs-string">'N'</span>,<span class="hljs-string">'E'</span>,<span class="hljs-string">'L'</span>,<span class="hljs-string">'3'</span>,<span class="hljs-string">'2'</span>,<span class="hljs-string">'.'</span>,<span class="hljs-string">'D'</span>,<span class="hljs-string">'L'</span>,<span class="hljs-string">'L'</span>,<span class="hljs-string">'\x00'</span> };<span class="hljs-type">char</span> api[] = { <span class="hljs-string">'W'</span>,<span class="hljs-string">'i'</span>,<span class="hljs-string">'n'</span>,<span class="hljs-string">'E'</span>,<span class="hljs-string">'x'</span>,<span class="hljs-string">'e'</span>,<span class="hljs-string">'c'</span>,<span class="hljs-string">'\x00'</span> };_PEB* peb = <span class="hljs-built_in">NtCurrentTeb</span>()->ProcessEnvironmentBlock;LIST_ENTRY* first = peb->Ldr->InMemoryOrderModuleList.Flink;LIST_ENTRY* ptr = first;<span class="hljs-keyword">do</span> {LDR_DATA_TABLE_ENTRY* dte = (LDR_DATA_TABLE_ENTRY*)((BYTE*)ptr - <span class="hljs-number">0x8</span>);BYTE* baseAddress = (BYTE*)dte->DllBase;ptr = ptr->Flink;<span class="hljs-keyword">if</span> (!baseAddress)<span class="hljs-keyword">continue</span>;PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)baseAddress;PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(baseAddress + dosHeader->e_lfanew);DWORD iedRVA = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;<span class="hljs-keyword">if</span> (!iedRVA)<span class="hljs-keyword">continue</span>;PIMAGE_EXPORT_DIRECTORY ied = (PIMAGE_EXPORT_DIRECTORY)(baseAddress + iedRVA);<span class="hljs-keyword">if</span> (<span class="hljs-built_in">getunicodeHash</span>(((<span class="hljs-keyword">decltype</span>(dte->FullDllName)*)(DWORD*)&(dte->Reserved4))->Buffer) == <span class="hljs-built_in">getHash</span>(dllname)) {DWORD* nameRVAs = (DWORD*)(baseAddress + ied->AddressOfNames);<span class="hljs-keyword">for</span> (DWORD i = <span class="hljs-number">0</span>; i < ied->NumberOfNames; i++) {<span class="hljs-type">char</span>* funcName = (<span class="hljs-type">char</span>*)(baseAddress + nameRVAs[i]);<span class="hljs-keyword">if</span> (<span class="hljs-built_in">getHash</span>(funcName) == <span class="hljs-built_in">getHash</span>(api)) {WORD ordinal = ((WORD*)(baseAddress + ied->AddressOfNameOrdinals))[i];DWORD functionRVA = ((DWORD*)(baseAddress + ied->AddressOfFunctions))[ordinal];<span class="hljs-keyword">return</span> baseAddress + functionRVA;}}}} <span class="hljs-keyword">while</span> (ptr != first);<span class="hljs-keyword">return</span> <span class="hljs-literal">NULL</span>;}<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">func</span><span class="hljs-params">()</span> </span>{<span class="hljs-type">char</span> exec[] = { <span class="hljs-string">'c'</span>,<span class="hljs-string">'a'</span>,<span class="hljs-string">'l'</span>,<span class="hljs-string">'c'</span>,<span class="hljs-string">'\x00'</span>};<span class="hljs-keyword">decltype</span>(WinExec)* myWinExec = (<span class="hljs-keyword">decltype</span>(WinExec)*)<span class="hljs-built_in">getWinExec</span>();<span class="hljs-built_in">myWinExec</span>(exec, <span class="hljs-number">0</span>);}<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><span class="hljs-function"></span>{<span class="hljs-built_in">func</span>();<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;}</code></pre></div><p>上面代码执行完之后会弹出windows计算器</p><blockquote><p>这里不讲windows可利用shellcode的编写,cs,msf都已经提供了很好用的shellcode</p></blockquote><h1 id="提取"><a href="#提取" class="headerlink" title="提取"></a>提取</h1><p>shellcode的提取</p><blockquote><p>使用c++开发代码</p><p>更改VisualStudio编译配置</p><p>生成exe</p><p>在IDA下打开生成的exe,获得机器码</p></blockquote><p>开发代码我们已经完成了,接下来是编译</p><p>配置编译选项,下面很多是默认的</p><blockquote><p>release在调试工具栏</p></blockquote><p>使大小最小化</p><blockquote><p>项目 - (你项目名称的)属性 - c/c++ - 优化 - 最大优化(优选大小)</p></blockquote><p>内联函数扩展</p><blockquote><p>项目 - (你项目名称的)属性 - c/c++ - 优化 - 函数扩展(只适用于_inline(Ob1))</p></blockquote><p>启用内部函数</p><blockquote><p>项目 - (你项目名称的)属性 - c/c++ - 优化 - 启用函数选择(是)</p></blockquote><p>禁用安全检查(/Gs-)</p><blockquote><p>项目 - (你项目名称的)属性 - c/c++ - 代码生成 - 安全检查(禁用)</p></blockquote><p>启用函数级链接</p><blockquote><p>项目 - (你项目名称的)属性 - c/c++ - 代码生成 - 启用函数级链接(是)</p></blockquote><p>增量链接</p><blockquote><p>项目 - (你项目名称的)属性 - 链接器 - 常规 -启用增量链接 (否)</p></blockquote><p>生成映射文件</p><blockquote><p>项目 - (你项目名称的)属性 - 链接器 - 调试 - 生成映射文件 (是)</p><p>映射文件名随便写</p></blockquote><p>启用COMDAT折叠</p><blockquote><p>项目 - (你项目名称的)属性 - 链接器 - 优化 - 启用COMDAT折叠(是)</p></blockquote><p>函数顺序</p><blockquote><p>项目 - (你项目名称的)属性 - 链接器 - 优化 - 函数顺序 (function_order.txt)</p></blockquote><p>关闭SDL检查 </p><blockquote><p>项目 - (你项目名称的)属性 - c/c++ - SDL检查改为否</p></blockquote><p>生成exe文件,用ida打开</p>]]></content>
<categories>
<category>逆向</category>
</categories>
</entry>
<entry>
<title>intel x86寄存器及其汇编指令</title>
<link href="/article/ec08c5f4.html"/>
<url>/article/ec08c5f4.html</url>
<content type="html"><![CDATA[<p>intel x86架构,复杂指令集,intel公司最成功的cpu架构。</p><p>x86代表32位架构</p><blockquote><p>我们平时装计算机所说的64位,32位代表寻址能力不同,一些地方说是支持的内存,其本质还是寻址能力</p><p>32位最大寻址内存范围是2的32次方,即4GB</p><div class="code-wrapper"><pre><code class="hljs 1k">1B=1024K=2^10K1GB=1024B=2^10B∴4GB=2^2*2^10*2^10*2^10=2^(2+10+10+10)=2^32```</code></pre></div><p>64位的最大寻址能力是2的64次方,即16384GB</p><p>但是,实际上限于种种原因,目前Windows 7 64位版仅能使用最大为192GB内存。</p><p>intel 系列向下兼容</p></blockquote><p>具体发展历史和一些细节:<a href="https://baike.baidu.com/item/Intel%20x86/1012845?fr=aladdin">https://baike.baidu.com/item/Intel%20x86/1012845?fr=aladdin</a></p><h1 id="寄存器"><a href="#寄存器" class="headerlink" title="寄存器"></a>寄存器</h1><p>八个通用寄存器:EAX,EBX,ECX,EDX,ESP,EBP,ESI,EDI</p><p>一个标志寄存器:EFLAGS</p><p>五个控制寄存器:分别为CR0-CR4</p><p>八个调试寄存器:分别为DR0-DR7</p><p>四个系统地址寄存器:GDTR、IDTR、LDTR和TR</p><p>其他寄存器:EIP、TSC等</p><h3 id="通用寄存器"><a href="#通用寄存器" class="headerlink" title="通用寄存器"></a>通用寄存器</h3><p>八个通用寄存器大多时候可以通用,但是某些寄存器有隐含用法。</p><h4 id="EAX"><a href="#EAX" class="headerlink" title="EAX"></a>EAX</h4><p>累加器,很多加法乘法指令的缺省寄存器。</p><h4 id="EBX"><a href="#EBX" class="headerlink" title="EBX"></a>EBX</h4><p>基地址(base)寄存器, 在内存寻址时存放基地址。</p><h4 id="ECX"><a href="#ECX" class="headerlink" title="ECX"></a>ECX</h4><p>是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。 </p><h4 id="EDX"><a href="#EDX" class="headerlink" title="EDX"></a>EDX</h4><p>总是被用来放整数除法产生的余数。</p><h4 id="ESI-x2F-EDI"><a href="#ESI-x2F-EDI" class="headerlink" title="ESI/EDI"></a>ESI/EDI</h4><p>分别叫做”源/目标索引寄存器(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目的串. </p><blockquote><p>源串和目的串(也有的叫目标串):</p><p>如在strcpy(*d, *s);</p><p>这里s指向的字符串就是源字符串,d指向的为<em>目的</em>字符串</p></blockquote><h4 id="EBP"><a href="#EBP" class="headerlink" title="EBP"></a>EBP</h4><p>是基址指针(BASE POINTER),它最经常被用作高级语言函数调用的”框架指针”(frame pointer)</p><h4 id="ESP"><a href="#ESP" class="headerlink" title="ESP"></a>ESP</h4><p>专门用作堆栈指针,被形象地称为栈顶指针,堆栈的顶部是地址小的区域,压入堆栈的数据越多,ESP也就越来越小。在32位平台上,ESP每次减少4字节。</p><blockquote><p>一般esp到ebp这段空间就是当前栈</p></blockquote><h3 id="标志寄存器"><a href="#标志寄存器" class="headerlink" title="标志寄存器"></a>标志寄存器</h3><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141032834.png" alt="image-20220402141032834"></p><p>包含一组状态标志,系统标志以及一个控制标志</p><h4 id="CF"><a href="#CF" class="headerlink" title="CF"></a>CF</h4><p>若算术操作产生的结果在最高有效位(most-significant bit)发生进位或借位则将其置1,反之清零。</p><h4 id="PF"><a href="#PF" class="headerlink" title="PF"></a>PF</h4><p>如果结果的最低有效字节(least-significant byte)包含偶数个1位则该位置1,否则清零。</p><h4 id="AF"><a href="#AF" class="headerlink" title="AF"></a>AF</h4><p>如果算术操作在结果的第3位发生进位或借位则将该标志置1,否则清零。</p><h4 id="ZF"><a href="#ZF" class="headerlink" title="ZF"></a>ZF</h4><p>若结果为0则将其置1,反之清零。 </p><h4 id="SF"><a href="#SF" class="headerlink" title="SF"></a>SF</h4><p>该标志被设置为有符号整型的最高有效位。(0指示结果为正,反之则为负) </p><h4 id="OF"><a href="#OF" class="headerlink" title="OF"></a>OF</h4><p>如果整型结果是较大的正数或较小的负数,并且无法匹配目的操作数时将该位置1,反之清零。这个标志为带符号整型运算指示溢出状态。</p><h4 id="DF"><a href="#DF" class="headerlink" title="DF"></a>DF</h4><p>控制串指令(MOVS, CMPS, SCAS, LODS以及STOS)。设置DF标志使得串指令自动递减(从高地址向低地址方向处理字符串),清除该标志则使得串指令自动递增。STD以及CLD指令分别用于设置以及清除DF标志。</p><h4 id="TF"><a href="#TF" class="headerlink" title="TF"></a>TF</h4><p>将该位设置为1以允许单步调试模式,清零则禁用该模式。</p><h4 id="IF"><a href="#IF" class="headerlink" title="IF"></a>IF</h4><p>该标志用于控制处理器对可屏蔽中断请求的响应。置1以响应可屏蔽中断,反之则禁止可屏蔽中断。 </p><h4 id="IOPL"><a href="#IOPL" class="headerlink" title="IOPL"></a>IOPL</h4><p>指示当前运行任务的I/O特权级,正在运行任务的当前特权级(CPL)必须小于或等于I/O特权级才能允许访问I/O地址空间。这个域只能在CPL为0时才能通过POPF以及IRET指令修改。</p><h4 id="NT"><a href="#NT" class="headerlink" title="NT"></a>NT</h4><p>这个标志控制中断链和被调用任务。若当前任务与前一个执行任务相关则置1,反之则清零。 </p><h4 id="RF"><a href="#RF" class="headerlink" title="RF"></a>RF</h4><p>控制处理器对调试异常的响应。</p><h4 id="VM"><a href="#VM" class="headerlink" title="VM"></a>VM</h4><p>置1以允许虚拟8086模式,清除则返回保护模式。</p><h4 id="AC"><a href="#AC" class="headerlink" title="AC"></a>AC</h4><p>标志以及在CR0寄存器中的AM位置1时将允许内存引用的对齐检查,以上两个标志中至少有一个被清零则禁用对齐检查。</p><h4 id="VIF"><a href="#VIF" class="headerlink" title="VIF"></a>VIF</h4><p>该标志是IF标志的虚拟镜像,与VIP标志结合起来使用。使用这个标志以及VIP标志,并设置CR4控制寄存器中的VME标志就可以允许虚拟模式扩展</p><h4 id="VIP"><a href="#VIP" class="headerlink" title="VIP"></a>VIP</h4><p>该位置1以指示一个中断正在被挂起,当没有中断挂起时该位清零,与VIF标志结合使用。 </p><h4 id="ID"><a href="#ID" class="headerlink" title="ID"></a>ID</h4><p> 程序能够设置或清除这个标志指示了处理器对CPUID指令的支持。</p><h3 id="控制寄存器"><a href="#控制寄存器" class="headerlink" title="控制寄存器"></a>控制寄存器</h3><h4 id="CR0"><a href="#CR0" class="headerlink" title="CR0"></a>CR0</h4><p>PE:CR0的位0是启用保护标志。当设置该位时即开启了保护模式;当复位时即进入实地址模式。这个标志仅开启段级保护,而并没有启用 分页机制。若要启用 分页机制,那么PE和PG标志都要置位。</p><blockquote><p>分页机制:<a href="https://baike.baidu.com/item/%E5%88%86%E9%A1%B5">https://baike.baidu.com/item/分页</a></p></blockquote><p>PG:CR0的位31是分页标志。当设置该位时即开启了分页机制;当复位时则禁止分页机制,此时所有线性地址等同于 物理地址。在开启这个标志之前必须已经或者同时开启PE标志。即若要启用分页机制,那么PE和PG标志都要置位。</p><p>WP:对于Intel 80486或以上的CPU,CR0的位16是 写保护(Write Proctect)标志。当设置该标志时,处理器会禁止 超级用户程序(例如 特权级0的程序)向用户级只读页面执行写操作;当该位复位时则反之。该标志有利于UNIX类操作系统在创建进程时实现写时复制(Copy on Write)技术。<br>NE:对于Intel 80486或以上的CPU,CR0的位5是 协处理器错误(Numeric Error)标志。当设置该标志时,就启用了x87 协处理器错误的内部报告机制;若复位该标志,那么就使用PC形式的x87协处理器 错误报告机制。当NE为复位状态并且CPU的IGNNE输入引脚有信号时,那么数学协处理器x87错误将被忽略。当NE为复位状态并且CPU的IGNNE输入引脚无信号时,那么非屏蔽的数学协处理器x87错误将导致处理器通过FERR引脚在外部产生一个中断,并且在执行下一个等待形式浮点指令或WAIT/FWAIT指令之前立刻停止指令执行。CPU的FERR引脚用于仿真外部 协处理器80387的ERROR引脚,因此通常连接到中断控制器输入请求引脚上。NE标志、IGNNE引脚和FERR引脚用于利用外部逻辑来实现PC形式的外部 错误报告机制。</p><blockquote><p>启用保护模式PE(Protected Enable)位(位0)和开启 分页PG(Paging)位(位31)分别用于控制分段和分页机制。PE用于控制分段机制。如果PE=1,处理器就工作在开启分段机制环境下,即运行在保护模式下。如果PE=0,则处理器关闭了分段机制,并如同8086工作于实地址模式下。PG用于控制 分页机制。如果PG=1,则开启了 分页机制。如果PG=0, 分页机制被禁止,此时 线性地址被直接作为 物理地址使用。</p><p>如果PE=0、PG=0,处理器工作在实地址模式下;如果PG=0、PE=1,处理器工作在没有开启 分页机制的保护模式下;如果PG=1、PE=0,此时由于不在保护模式下不能启用分页机制,因此处理器会产生一个一般保护异常,即这种标志组合无效;如果PG=1、PE=1,则处理器工作在开启了分页机制的保护模式下。</p><p>当改变PE和PG位时,必须小心。只有当执行程序至少有部分代码和数据在线性地址空间和物理地址空间中具有相同地址时,我们才能改变PG位的设置。此时这部分具有相同地址的代码在 分页和未分页世界之间起着桥梁的作用。无论是否开启分页机制,这部分代码都具有相同的地址。另外,在开启分页(PG=1)之前必须先刷新页高速缓冲TLB。<br>在修改该了PE位之后程序必须立刻使用一条跳转指令,以刷新处理器执行管道中已经获取的不同模式下的任何指令。在设置PE位之前,程序必须初始化几个系统段和控制寄存器。在系统刚上电时,处理器被复位成PE=0和PG=0(即实模式状态),以允许引导代码在启用分段和分页机制之前能够初始化这些寄存器和数据结构。</p></blockquote><h4 id="CR2和CR3"><a href="#CR2和CR3" class="headerlink" title="CR2和CR3"></a>CR2和CR3</h4><p>CR2和CR3用于分页机制。CR3含有存放页目录表页面的物理地址,因此CR3也被称为PDBR。因为页目录表页面是页对齐的,所以该寄存器只有高20位是有效的。而低12位保留供更高级处理器使用,因此在往CR3中加载一个新值时低12位必须设置为0。</p><h3 id="调试寄存器"><a href="#调试寄存器" class="headerlink" title="调试寄存器"></a>调试寄存器</h3><h4 id="GDTR"><a href="#GDTR" class="headerlink" title="GDTR"></a>GDTR</h4><p>全局描述符表寄存器,用于存放全局描述符表GDT的32位的线性基地址和16位的表限长值。基地址指定GDT表中字节0在线性地址空间中的地址,表长度指明GDT表的字节长度值。指令LGDT和SGDT分别用于加载和保存GDTR寄存器的内容。在机器刚加电或处理器复位后,基地址被默认地设置为0,而长度值被设置成0xFFFF。在保护模式初始化过程中必须给GDTR加载一个新值。</p><h4 id="IDTR"><a href="#IDTR" class="headerlink" title="IDTR"></a>IDTR</h4><p>中断描述符表寄存器,与GDTR的作用类似,IDTR寄存器用于存放中断描述符表IDT的32位线性基地址和16位表长度值。指令LIDT和SIDT分别用于加载和保存IDTR寄存器的内容。在机器刚加电或处理器复位后,基地址被默认地设置为0,而长度值被设置成0xFFFF。</p><h4 id="LDTR"><a href="#LDTR" class="headerlink" title="LDTR"></a>LDTR</h4><p>用于存放局部描述符表LDT的32位线性基地址、16位段限长和描述符属性值。指令LLDT和SLDT分别用于加载和保存LDTR寄存器的段描述符部分,包含LDT</p><h3 id="EIP"><a href="#EIP" class="headerlink" title="EIP"></a>EIP</h3><p>存储我们cpu要读取指令的地址</p><h3 id="TSC"><a href="#TSC" class="headerlink" title="TSC"></a>TSC</h3><p>一个用于时间戳计数器的64位的寄存器,它在每个时钟信号到来时加一</p><h2 id="指令集"><a href="#指令集" class="headerlink" title="指令集"></a>指令集</h2><h3 id="数据传送指令"><a href="#数据传送指令" class="headerlink" title="数据传送指令"></a>数据传送指令</h3><h4 id="MOV"><a href="#MOV" class="headerlink" title="MOV"></a>MOV</h4><p>mov指令将第二个操作数(可以是寄存器的内容、内存中的内容或值)复制到第一个操作数(寄存器或内存)。mov不能用于直接从内存复制到内存</p><h4 id="push"><a href="#push" class="headerlink" title="push"></a>push</h4><p>push指令将操作数压入内存的栈中</p><h4 id="pop"><a href="#pop" class="headerlink" title="pop"></a><strong>pop</strong></h4><p>与push相反,将操作数从栈中取出</p><h4 id="lea"><a href="#lea" class="headerlink" title="lea"></a><strong>lea</strong></h4><p> lea实际上是一个载入有效地址指令,将第二个操作数表示的地址载入到第一个操作数(寄存器)中 lea实际上是一个载入有效地址指令,将第二个操作数表示的地址载入到第一个操作数(寄存器)中。</p><h3 id="算术和逻辑指令"><a href="#算术和逻辑指令" class="headerlink" title="算术和逻辑指令"></a>算术和逻辑指令</h3><h4 id="ADD"><a href="#ADD" class="headerlink" title="ADD"></a>ADD</h4><p>将两个操作数相加,且将相加后的结果保存到第一个操作数中。</p><h4 id="SUB"><a href="#SUB" class="headerlink" title="SUB"></a>SUB</h4><p>第一个操作数减去第二个操作数,并将相减后的值保存在第一个操作数。</p><h4 id="INC和DEC"><a href="#INC和DEC" class="headerlink" title="INC和DEC"></a>INC和DEC</h4><p>inc,dec分别表示将操作数自加1,自减1。</p><h4 id="IMUL"><a href="#IMUL" class="headerlink" title="IMUL"></a>IMUL</h4><p>整数相乘指令,它有两种指令格式,一种为两个操作数,将两个操作数的值相乘,并将结果保存在第一个操作数中,第一个操作数必须为寄存器;第二种格式为三个操作数,其语义为:将第二个和第三个操作数相乘,并将结果保存在第一个操作数中,第一个操作数必须为寄存器</p><h4 id="IDIV"><a href="#IDIV" class="headerlink" title="IDIV"></a>IDIV</h4><p>idiv指令完成整数除法操作,idiv只有一个操作数,此操作数为除数,而被除数则为EDX:EAX中的内容(一个64位的整数)。</p><h4 id="AND-OR-XOR"><a href="#AND-OR-XOR" class="headerlink" title="AND, OR, XOR"></a>AND, OR, XOR</h4><p>逻辑与、逻辑或、逻辑异或操作指令,用于操作数的位操作,操作结果放在第一个操作数中。</p><h4 id="NOT"><a href="#NOT" class="headerlink" title="NOT"></a>NOT</h4><p>位翻转指令,将操作数中的每一位翻转,即0->1, 1->0。</p><h4 id="NEG"><a href="#NEG" class="headerlink" title="NEG"></a>NEG</h4><p>取负指令。</p><h4 id="SHL-SHR"><a href="#SHL-SHR" class="headerlink" title="SHL, SHR"></a>SHL, SHR</h4><p>位移指令,有两个操作数,第一个操作数表示被操作数,第二个操作数指示位移的数量。</p><h3 id="控制转移指令"><a href="#控制转移指令" class="headerlink" title="控制转移指令"></a>控制转移指令</h3><h4 id="JMP"><a href="#JMP" class="headerlink" title="JMP"></a>JMP</h4><p>控制转移到label所指示的地址。</p><h4 id="jcondition"><a href="#jcondition" class="headerlink" title="jcondition"></a>jcondition</h4><p>条件转移指令,条件转移指令依据机器状态字中的一些列条件状态转移。机器状态字中包括指示最后一个算数运算结果是否为0,运算结果是否为负数等。</p><blockquote><p>je <label> (jump when equal)<br>jne <label> (jump when not equal)<br>jz <label> (jump when last result was zero)<br>jg <label> (jump when greater than)<br>jge <label> (jump when greater than or equal to)<br>jl <label> (jump when less than)<br>jle <label>(jump when less than or equal to)</p></blockquote><h4 id="CMP"><a href="#CMP" class="headerlink" title="CMP"></a>CMP</h4><p>cmp指令比较两个操作数的值,并根据比较结果设置机器状态字中的条件码。此指令与sub指令类似,但是cmp不用将计算结果保存在操作数中。</p><h4 id="CALL-RET"><a href="#CALL-RET" class="headerlink" title="CALL, RET"></a>CALL, RET</h4><p>这两条指令实现子程序(过程、函数等意思)的调用及返回。call指令首先将当前执行指令地址入栈,然后无条件转移到由标签指示的指令。与其它简单的跳转指令不同,call指令保存调用之前的地址信息(当call指令结束后,返回到调用之前的地址)。</p><p>ret指令实现子程序的返回机制,ret指令弹出栈中保存的指令地址,然后无条件转移到保存的指令地址执行。</p>]]></content>
<categories>
<category>逆向</category>
</categories>
</entry>
<entry>
<title>ARM寄存器及其汇编指令</title>
<link href="/article/c21195a7.html"/>
<url>/article/c21195a7.html</url>
<content type="html"><![CDATA[<h2 id="ARM处理器"><a href="#ARM处理器" class="headerlink" title="ARM处理器"></a>ARM处理器</h2><p>第一款RISC(精简指令集)微处理器,(arm)32位设计,但配有16位指令集(thumb)</p><p>32位和16位可以相互调用,且开销几乎为0</p><p>使用大量寄存器,功耗低,效率高</p><p>ps:具体发展,系列之类请参考百度百科:<a href="https://baike.baidu.com/item/arm/5907">https://baike.baidu.com/item/arm/5907</a></p><h2 id="arm寄存器"><a href="#arm寄存器" class="headerlink" title="arm寄存器"></a>arm寄存器</h2><p>arm包括37个寄存器,都是32位</p><p>31个通用寄存器,6个状态寄存器</p><p>arm有7种处理器模式,每个模式中有一组相应的寄存器</p><p>在任何一种处理器模式下可见的寄存器包括15个通用寄存器(r0-r14),一个或者两个状态寄存器,程序技术器(pc)</p><p>所有寄存器中,有些是各模式公用的物理寄存器,有些是某个模式独立拥有的物理寄存器</p><blockquote><p> 七个处理器模式: 用户模式(User),快速中断模式(FIQ),普通中断模式(IRQ),管理模式(Svc),数据访问中止模</p><p>(Abort),未定义指令中止模式(Und),系统模式(Sys)</p></blockquote><h3 id="寄存器用途"><a href="#寄存器用途" class="headerlink" title="寄存器用途"></a>寄存器用途</h3><p>r0 - r3:传参</p><p>r4 - r11:保存局部变量,但在thumb(16位程序)中,通常只能用r4-r7来保存局部变量</p><p>r12:ip寄存器 </p><p>r13:栈帧,即sp</p><p>r14:lr,被称为连接寄存器,用于保存子程序以及中断的返回地址</p><p>r15:程序计数器,即pc,但由于arm使用的是三级流水线结构,所以我们读取正确的pc的值之后应该在该值基础上加八个字节,即指向pc下两条指令的地址</p><blockquote><p>ps:关于三级流水线,另一片相关文章会具体解释</p></blockquote><p>CPSR:当前程序状态寄存器,在任何模式下可以被访问。包含条件标志位、中断禁止位、当前处理器模式标志以及其他的一些控制和状态位。CPSR在用户编程时由于存储条件码。</p><p>SPSR:每一种模式下都有一个状态寄存器SPSR,用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。用户模式和系统模式不是异常状态,所以没有SPSR,在这两种模式下访问SPSR,将产生不可预知的后果。</p><h3 id="CPSR详解:"><a href="#CPSR详解:" class="headerlink" title="CPSR详解:"></a>CPSR详解:</h3><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140909199.png" alt="image-20220402140909199"></p><blockquote><p>ps:长度为32</p></blockquote><p>cpsr包括条件标志位、中断禁止位、当前处理器模式标志以及其他的一些控制和状态位</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140916144.png" alt="image-20220402140916144"></p><p>通过上图就可以理解cpsr_cxsf的意思了</p><h4 id="条件码标志"><a href="#条件码标志" class="headerlink" title="条件码标志"></a>条件码标志</h4><p>N:结果是有符号的二进制补码情况下,结果为负的话N=1,结果为非负的话N=0</p><p>Z:结果如果为零的话Z=1,结果非零的话Z=0</p><p>C:有多种情况</p><blockquote><p>对于加法指令(包括比较指令CMN),产生进位的话C=1,否则C=0。</p><p>对于减法指令(包括比较指令CMP),如果产生借位,则C=0;否则C=1。</p><p>对于有移位操作的非法指令,C为移位操作中最后移出位的值。</p><p>对于其他指令,C通常不变。</p><p>ps:比较指令CMN与CMP其实才是算数指令,之后会有详解</p></blockquote><p>V:对于加减法指令,在操作数和结果是有符号的整数时,如果发生溢出,则V=1;如果无溢出发生,则V=0;对于其他指令,V通常不发生变化</p><h2 id="ARM指令集"><a href="#ARM指令集" class="headerlink" title="ARM指令集"></a>ARM指令集</h2><h3 id="指令格式"><a href="#指令格式" class="headerlink" title="指令格式"></a>指令格式</h3><blockquote><p> <opcode> {<cond>} {S} <Rd> , <Rn> {,<opcode2>}</p></blockquote><p><code><></code>内是必须项,<code>{}</code>内是可选项,<code>不写</code>代表无条件执行</p><p>opcode 指令助记符,如LDR,STR 等</p><p>cond 执行条件,如EQ,NE 等</p><p>S 是否影响CPSR 寄存器的值,书写时影响CPSR,否则不影响</p><p>Rd 目标寄存器</p><p>Rn 第一个操作数的寄存器</p><p>operand2 第二个操作数</p><h3 id="储存器访问指令"><a href="#储存器访问指令" class="headerlink" title="储存器访问指令"></a>储存器访问指令</h3><p>ARM 处理是加载/存储体系结构的典型的RISC处理器</p><p>对存储器的访问只能使用加载和存储指令实现</p><p>ARM 的加载/存储指令是可以实现字、半字、无符/有符字节操作</p><p>批量加载/存储指令可实现一条指令加载/存储多个寄存器的内容</p><p>SWP指令是一条寄存器和存储器内容交换的指令,可用于信号量操作等</p><p>ARM 处理器是冯.诺依曼存储结构,程序空间、RAM 空间及IO 映射空间统一编址,除对对RAM 操作以外,对外围IO、程序数据的访问均要通过加载/存储指令进行</p><p>下图给出ARM存储访问指令表</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140923882.png" alt="image-20220402140923882"></p><h4 id="LDR-x2F-STR"><a href="#LDR-x2F-STR" class="headerlink" title="LDR/STR"></a>LDR/STR</h4><blockquote><p>LDR{cond}{T} Rd,<地址>;</p></blockquote><blockquote><p>STR{cond}{T} Rd,<地址>;</p></blockquote><p>LDR从内存中读取数据放入寄存器,STR用于将寄存器内的数据放到内存</p><blockquote><p>LDR R2, [R7,#0x10+var_C] 将<code>R7 + 0x10+var_C</code>地址的数据放到R2</p><p>STR R3, [R7,#0x10+var_4] 将R3的数据储存在<code>R7 + 0x10+var_4</code></p></blockquote><p>{T}为可选项,若指令有T,那么即使处理器是在特权模式下,存储系统也将访问看成是处理器是在用户模式下</p><p>T在用户模式下无效,不能与前索引偏移一起使用T</p><blockquote><p>LDR Rd,[Rn] 零偏移,将Rn的值作为内存地址</p><p>LDR Rd,[Rn,#0x04]! 前索引偏移,将Rn+0x04地址的值放到Rd,并且<code>更新Rn</code>的值为Rn = Rn + 0x04,如果没有后边感叹号,则Rn不更新</p><p>LDR Rd,label ; 程序相对偏移,label 为程序标号,label 必须是在当前指令的±4KB范围内</p><p>LDR Rd,[Rn],#0x04 后索引偏移,将Rn中的地址的数据加载到Rd中,然后将Rn更新Rn = Rn + 0x04</p></blockquote><p>ps:前索引偏移就是在索引前偏移,看有无!决定时候更新寄存器的内容。后索引偏移就是在索引后偏移,索引时并不偏移,索引后更新寄存器内容</p><h4 id="LDM-x2F-STM"><a href="#LDM-x2F-STM" class="headerlink" title="LDM/STM"></a><strong>LDM/STM</strong></h4><blockquote><p>LDM{cond}<模式> Rn{!},reglist{^}</p><p>STM{cond}<模式> Rn{!},reglist{^}</p></blockquote><p>LDM 加载多个寄存器,STM储存多个寄存器</p><p>主要用途是现场保护、数据复制、参数传送等</p><p>其模式有8种,如下所列:(前面4 种用于数据块的传输,后面4 种是堆栈操作)</p><blockquote><p>(1) IA:每次传送后地址加4</p><p>(2) IB:每次传送前地址加4</p><p>(3) DA:每次传送后地址减4</p><p>(4) DB:每次传送前地址减4</p><p>(5) FD:满递减堆栈</p><p>(6) ED:空递增堆栈</p><p>(7) FA:满递增堆栈</p><p>(8) EA:空递增堆栈</p></blockquote><p>寄存器Rn为基址寄存器,装有传送数据的初始地址,Rn 不允许为R15;缀<code>!</code>表示最后的地址写回到Rn中</p><p>寄存器列表reglist 可包含多于一个寄存器或寄存器范围,使用“,”分开,如{R1,R2,R6-R9},寄存器排列由小到大排列</p><p><code>^</code>后缀不允许在用户模式呈系统模式下使用,若在LDM 指令用寄存器列表中包含有PC 时使用,那么除了正常的多寄存器传送外,将SPSR 拷贝到CPSR 中,这可用于异常处理返回</p><p>使用<code>^</code>后缀进行数据传送且寄存器列表不包含PC时,加载/存储的是用户模式的寄存器,而不是当前模式的寄存器</p><blockquote><p>LDMIA R0!,{R3-R9} ;加载R0 指向的地址上的多字数据,保存到R3~R9中,R0 值更新</p><p>STMIA R1!,{R3-R9} ;将R3~R9 的数据存储到R1 指向的地址上,R1值更新</p><p>STMFD SP!,{R0-R7,LR} ;现场保存,将R0~R7、LR入栈</p><p>LDMFD SP!,{R0-R7,PC}^;恢复现场,异常处理返回</p></blockquote><h4 id="SWP-寄存器和存储器交换指令"><a href="#SWP-寄存器和存储器交换指令" class="headerlink" title="SWP 寄存器和存储器交换指令"></a>SWP 寄存器和存储器交换指令</h4><blockquote><p> SWP{cond}{B} Rd,Rm,[Rn]</p></blockquote><p>SWP指令用于将一个内存单元(该单元地址放在寄存器Rn中)的内容读取到一个寄存器Rd中,同时将另一个寄存器Rm 的内容写入到该内存单元中</p><p>B 为可选后缀,若有B,则交换字节,否则交换32 位字:Rd 为数据从存储器加载到的寄存器;Rm的数据用于存储到存储器中,若Rm 与Rn 相同,则为寄存器与存储器内容进行交换;Rn 为要进行数据交换的存储器地址,Rn 不能与Rd 和Rm 相同</p><blockquote><p>SWP R1,R1,[R0] ; 将R1 的内容与R0 指向的存储单元的内容进行交换</p><p>SWP R1,R2,,[R0] ; 将R0 指向的存储单元内容读取一字节数据到R1中(高24 位清零) ; 并将R2 的内容写入到该内存单元中(最低字节有效)</p></blockquote><h3 id="ARM-数据处理指令"><a href="#ARM-数据处理指令" class="headerlink" title="ARM 数据处理指令"></a>ARM 数据处理指令</h3><h4 id="MOV-数据传送指令"><a href="#MOV-数据传送指令" class="headerlink" title="MOV 数据传送指令"></a>MOV 数据传送指令</h4><blockquote><p>MOV{cond}{S} Rd,operand2</p></blockquote><p>将8 位立即数或寄存器(operant2)传送到目标寄存器Rd,可用于移位运算等操作</p><blockquote><p>MOV R1#0x10 ;R1=0x10</p><p>MOV R0,R1 ;R0=R1</p><p>MOVS R3,R1,LSL #2 ;R3=R1<<2,并影响标志位</p><p>MOV PC,LR ;PC=LR ,子程序返回</p></blockquote><h4 id="MVN-数据非传送指令"><a href="#MVN-数据非传送指令" class="headerlink" title="MVN 数据非传送指令"></a>MVN 数据非传送指令</h4><blockquote><p>MVN{cond}{S} Rd,operand2</p></blockquote><p>将8 位图立即数或寄存器(operand2)按位取反后传送到目标寄存器(Rd),因为其具有取反功能,所以可以装载范围更广的立即数</p><blockquote><p>MVN R1,#0xFF ;R1=0xFFFFFF00</p><p>MVN R1,R2 ;将R2 取反,结果存到R1</p></blockquote><h4 id="ADD-加法运算指令"><a href="#ADD-加法运算指令" class="headerlink" title="ADD 加法运算指令"></a>ADD 加法运算指令</h4><blockquote><p>ADD{cond}{S} Rd,Rn,operand2</p></blockquote><p> 将operand2 数据与Rn 的值相加,结果保存到Rd 寄存器</p><blockquote><p>ADDS R1,R1,#1 ;R1=R1+1</p><p>ADD R1,R1,R2 ;R1=R1+R2</p><p>ADDS R3,R1,R2,LSL #2 ;R3=R1+R2<<2</p></blockquote><h4 id="SUB-减法运算指令"><a href="#SUB-减法运算指令" class="headerlink" title="SUB 减法运算指令"></a>SUB 减法运算指令</h4><blockquote><p>SUB{cond}{S} Rd,Rn,operand2</p></blockquote><p>用寄存器Rn 减去operand2。结果保存到Rd 中</p><blockquote><p>SUBS R0,R0,#1 ;R0=R0-1</p><p>SUBS R2,R1,R2 ;R2=R1-R2</p><p>SUB R6,R7,#0x10 ;R6=R7-0x10</p></blockquote><h4 id="RSB-逆向减法指令"><a href="#RSB-逆向减法指令" class="headerlink" title="RSB 逆向减法指令"></a>RSB 逆向减法指令</h4><blockquote><p>RSB{cond}{S} Rd,Rn,operand2</p></blockquote><p>用寄存器operand2 减法Rn,结果保存到Rd 中</p><blockquote><p>RSB R3,R1,#0xFF00 ;R3=0xFF00-R1</p><p>RSBS R1,R2,R2,LSL #2 ;R1=R2<<2-R2=R2×3</p><p>RSB R0,R1,#0 ;R0=-R1</p></blockquote><h4 id="ADC-带进位加法指令"><a href="#ADC-带进位加法指令" class="headerlink" title="ADC 带进位加法指令"></a><strong>ADC</strong> 带进位加法指令</h4><blockquote><p>ADC{cond}{S} Rd,Rn,operand2</p></blockquote><p>将operand2 的数据与Rn 的值相加,再加上CPSR中的C 条件标志位,结果保存到Rd 寄存器</p><blockquote><p>ADC R1,R1,R3 ;使用ADC 实现64 位加法,R1=R1+R3</p></blockquote><h4 id="SBC-带进位减法指令"><a href="#SBC-带进位减法指令" class="headerlink" title="SBC 带进位减法指令"></a><strong>SBC</strong> 带进位减法指令</h4><blockquote><p>SCB{cond}{S}Rd,Rn,operand2</p></blockquote><p>用寄存器Rn 减去operand2,再减去CPSR 中的C条件标志位的非(即若C 标志清零,则结果减去1),结果保存到Rd 中</p><blockquote><p>SBC R1,R1,R3 ;使用SBC 实现64 位减法,R1 = R1 - R3</p></blockquote><h4 id="RSC-带进位逆向减法指令"><a href="#RSC-带进位逆向减法指令" class="headerlink" title="RSC 带进位逆向减法指令"></a><strong>RSC</strong> 带进位逆向减法指令</h4><blockquote><p> RSC{cond}{S} Rd,Rn,operand2</p></blockquote><p>用寄存器operand2 减去Rn,再减去CPSR 中的C条件标志位,结果保存到Rd 中</p><blockquote><p>RSC R3,R1,#0 ;使用RSC 指令实现求64 位数值的负数 R3 = 0 -R1</p></blockquote><h4 id="AND-逻辑与操作指令"><a href="#AND-逻辑与操作指令" class="headerlink" title="**AND **逻辑与操作指令"></a>**AND **逻辑与操作指令</h4><blockquote><p>AND{cond}{S} Rd,Rn,operand2</p></blockquote><p>将operand2 值与寄存器Rn 的值按位作逻辑与操作,结果保存到Rd中</p><p><code>逻辑与操作,都为1则返回1</code></p><blockquote><p>ANDS R0,R0,#x01 ;R0=R0&0x01,取出最低位数据</p><p>AND R2,R1,R3 ;R2=R1&R3</p></blockquote><h4 id="ORR-逻辑或操作指令"><a href="#ORR-逻辑或操作指令" class="headerlink" title="**ORR **逻辑或操作指令"></a>**ORR **逻辑或操作指令</h4><blockquote><p>ORR{cond}{S} Rd,Rn,operand2</p></blockquote><p>将operand2 的值与寄存器Rn的值按位作逻辑或操作,结果保存到Rd 中</p><blockquote><p>ORR R0,R0,#x0F ;将R0 的低4 位置1</p><p>MOV R1,R2,LSR #4</p><p>ORR R3,R1,R3,LSL #8 ;使用ORR 指令将近R2 的高8位数据移入到R3 低8 位中</p></blockquote><h4 id="EOR-逻辑异或操作指令"><a href="#EOR-逻辑异或操作指令" class="headerlink" title="**EOR **逻辑异或操作指令"></a>**EOR **逻辑异或操作指令</h4><blockquote><p>EOR{cond}{S}Rd,Rn,operand2</p></blockquote><p>将operand2 的值与寄存器Rn 的值按位作逻辑异或操作,结果保存到Rd中</p><blockquote><p>EOR R1,R1,#0x0F ;将R1 的低4 位取反</p><p>EOR R2,R1,R0 ;R2=R1^R0</p><p>EORS R0,R5,#0x01 ;将R5 和0x01 进行逻辑异或,结果保存到R0,并影响标志位</p></blockquote><h4 id="BIC-位清除指令"><a href="#BIC-位清除指令" class="headerlink" title="BIC 位清除指令"></a><strong>BIC</strong> 位清除指令</h4><blockquote><p> BIC{cond}{S}Rd,Rn,operand2</p></blockquote><p>将寄存器Rn 的值与operand2 的值的反码按位作逻辑与操作,结果保存到Rd中。</p><blockquote><p>BIC R1,R1,#0x0F ;将R1 的低4 位清零,其它位不变</p><p>BIC R1,R2,R3 ;将拭的反码和R2 相逻辑与,结果保存到R1</p></blockquote><h4 id="CMP-比较指令"><a href="#CMP-比较指令" class="headerlink" title="CMP 比较指令"></a><strong>CMP</strong> 比较指令</h4><blockquote><p>CMP{cond} Rn,operand2</p></blockquote><p>指令使用寄存器Rn 的值减去operand2 的值,根据操作的结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行</p><p>CMP 指令不保存运算结果</p><blockquote><p>CMP R1,#10 ;R1 与10 比较,设置相关标志位</p><p>CMP R1,R2 ;R1 与R2 比较,设置相关标志位</p></blockquote><h4 id="CMN-负数比较指令"><a href="#CMN-负数比较指令" class="headerlink" title="**CMN **负数比较指令"></a>**CMN **负数比较指令</h4><blockquote><p>CMN{cond} Rn,operand2</p></blockquote><p>指令使用寄存器Rn 与值加上operand2 的值,根据操作的结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行</p><blockquote><p>CMN R0,#1 ;R0+1,判断R0 是否为1 的补码,若是Z 置位</p><p>CMN 指令与ADDS 指令的区别在于CMN 指令不保存运算结果。CMN指令可用于负数比较,比如CMNR0,#1 指令则表示R0 与-1 比较,若R0 为-(即1 的补码),则Z 置位,否则Z复位。</p></blockquote><h4 id="TST-位测试指令"><a href="#TST-位测试指令" class="headerlink" title="TST 位测试指令"></a><strong>TST</strong> 位测试指令</h4><blockquote><p> TST{cond} Rn,operand2</p></blockquote><p>指令将寄存器Rn 的值与operand2 的值按位作逻辑与操作,根据操作的结果更新CPSR中相应的条件标志位(当结果为0时,EQ位被设置),以便后面指令根据相应的条件标志来判断是否执行</p><blockquote><p>TST R0,#0x01 ;判断R0 的最低位是否为0</p><p>TST R1,#0x0F ;判断R1 的低4 位是否为0</p><p>TST 指令与ANDS 指令的区别在于TST4 指令不保存运算结果。TST指令通常于EQ、NE条件码配合使用,当所有测试位均为0 时,EQ 有效,而只要有一个测试为不为0,则NE 有效。</p></blockquote><h4 id="TEQ-相等测试指令"><a href="#TEQ-相等测试指令" class="headerlink" title="TEQ 相等测试指令"></a><strong>TEQ</strong> 相等测试指令</h4><blockquote><p> TEQ{cond} Rn,operand2</p></blockquote><p>指令寄存器Rn 的值与operand2 的值按位作逻辑异或操作,根据操作的结果更新CPSR中相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行</p><blockquote><p>TEQ R0,R1 ;比较R0 与R1 是否相等(不影响V 位和C 位)</p><p>TST 指令与EORS 指令的区别在于TST 指令不保存运算结果。使用TEQ进行相等测试,常与EQNE 条件码配合使用,当两个数据相等时,EQ 有效,否则NE 有效。</p></blockquote><h4 id="MUL-32-位乘法指令"><a href="#MUL-32-位乘法指令" class="headerlink" title="MUL 32 位乘法指令"></a><strong>MUL</strong> 32 位乘法指令</h4><blockquote><p> MUL{cond}{S} Rd,Rm,Rs</p></blockquote><p>指令将Rm 和Rs 中的值相乘,结果的低32 位保存到Rd中</p><blockquote><p>MUL R1,R2,R3 ;R1=R2×R3</p><p>MULS R0,R3,R7 ;R0=R3×R7,同时设置CPSR 中的N位和Z 位</p></blockquote><h4 id="MLA-32-位乘加指令"><a href="#MLA-32-位乘加指令" class="headerlink" title="MLA 32 位乘加指令"></a><strong>MLA</strong> 32 位乘加指令</h4><blockquote><p>MLA{cond}{S} Rd,Rm,Rs,Rn</p></blockquote><p> 指令将Rm 和Rs 中的值相乘,再将乘积加上第3 个操作数,结果的低32位保存到Rd 中</p><blockquote><p>MLA R1,R2,R3,R0 ;R1=R2×R3+R0</p></blockquote><h4 id="UMULL-64-位无符号乘法指令"><a href="#UMULL-64-位无符号乘法指令" class="headerlink" title="**UMULL ** 64 位无符号乘法指令"></a>**UMULL ** 64 位无符号乘法指令</h4><blockquote><p> UMULL{cond}{S} RdLo,RdHi,Rm,Rs</p></blockquote><p>指令将Rm 和Rs 中的值作无符号数相乘,结果的低32位保存到RsLo 中,而高32 位保存到RdHi 中</p><blockquote><p>UMULL R0,R1,R5,R8 ;(R1、R0)=R5×R8</p></blockquote><h4 id="UMLAL-64-位无符号乘加指令"><a href="#UMLAL-64-位无符号乘加指令" class="headerlink" title="UMLAL 64 位无符号乘加指令"></a><strong>UMLAL</strong> 64 位无符号乘加指令</h4><blockquote><p> UMLAL{cond}{S} RdLo,RdHi,Rm,Rs</p></blockquote><p>指令将Rm 和Rs 中的值作无符号数相乘,64 位乘积与RdHi、RdLo相加,结果的低32 位保存到RdLo 中,而高32 位保存到RdHi 中</p><blockquote><p>UMLAL R0,R1,R5,R8;(R1,R0)=R5×R8+(R1,R0)</p></blockquote><h4 id="SMULL-64-位有符号乘法指令"><a href="#SMULL-64-位有符号乘法指令" class="headerlink" title="**SMULL **64 位有符号乘法指令"></a>**SMULL **64 位有符号乘法指令</h4><blockquote><p> SMULL{cond}{S} RdLo,RdHi,Rm,Rs</p></blockquote><p>指令将Rm 和Rs 中的值作有符号数相乘,结果的低32位保存到RdLo 中,而高32 位保存到RdHi 中</p><blockquote><p> SMULL R2,R3,R7,R6 ;(R3,R2)=R7×R6</p></blockquote><h4 id="SMLAL-64-位有符号乘加指令"><a href="#SMLAL-64-位有符号乘加指令" class="headerlink" title="SMLAL 64 位有符号乘加指令"></a><strong>SMLAL</strong> 64 位有符号乘加指令</h4><blockquote><p> SMLAL{cond}{S} RdLo,RdHi,Rm,Rs</p></blockquote><p>指令将Rm 和Rs 中的值作有符号数相乘,64 位乘积与RdHi、RdLo,相加,结果的低32位保存到RdLo 中,而高32 位保存到RdHi 中</p><blockquote><p>SMLAL R2,R3,R7,R6;(R3,R2)=R7×R6+(R3,R2)</p></blockquote><h3 id="ARM跳转指令"><a href="#ARM跳转指令" class="headerlink" title="ARM跳转指令"></a>ARM跳转指令</h3><h4 id="B"><a href="#B" class="headerlink" title="B"></a><strong>B</strong></h4><blockquote><p>B{cond} label</p></blockquote><p>跳转到指定的地址执行程序,跳转到指令B 限制在当前指令的±32Mb 的范围内</p><blockquote><p>B WAITA ;跳转到WAITA 标号处</p><p>B 0x1234 ;跳转到绝对地址0x1234 处</p></blockquote><h4 id="BL-带链接的跳转指令"><a href="#BL-带链接的跳转指令" class="headerlink" title="**BL **带链接的跳转指令"></a>**BL **带链接的跳转指令</h4><blockquote><p>BL{cond} label</p></blockquote><p>指令将下一条指令的地址拷贝到R14(即LR)链接寄存器中,然后跳转到指定地址运行程序</p><p>跳转指令B 限制在当前指令的±32MB 的范围内。BL 指令用于子程序调用</p><blockquote><p>BL DELAY</p></blockquote><h4 id="BX-带状态切换的跳转指令"><a href="#BX-带状态切换的跳转指令" class="headerlink" title="BX 带状态切换的跳转指令"></a><strong>BX</strong> 带状态切换的跳转指令</h4><blockquote><p> BX{cond} Rm</p></blockquote><p>跳转到Rm 指定的地址执行程序,若Rm 的位[0]为1,则跳转时自动将CPSR 中的标志T 置位,即把目标地址的代码解释为Thumb代码;若Rm 的位[0]为0,则跳转时自动将CPSR 中的标志T 复位,即把目标地址的代码解释为ARM代码</p><blockquote><p>ADRL R0,ThumbFun+1</p><p>BX R0 ;跳转到R0 指定的地址,并根据R0 的最低位来切换处理器状态</p></blockquote><h4 id="BLX"><a href="#BLX" class="headerlink" title="BLX"></a>BLX</h4><p>BLX目标地址:跳转,改变状态及保存PC值</p><h3 id="ARM-协处理器指令"><a href="#ARM-协处理器指令" class="headerlink" title="ARM 协处理器指令"></a>ARM 协处理器指令</h3><h4 id="CDP-协处理器数据操作指令"><a href="#CDP-协处理器数据操作指令" class="headerlink" title="CDP 协处理器数据操作指令"></a>CDP 协处理器数据操作指令</h4><blockquote><p>CDP{cond}coproc,opcodel,CRd,CRn,CRm{,opcode2}</p><p>coproc 指令操作的协处理器名。标准名为pn,n 为0~15。</p><p>opcodel 协处理器的特定操作码。</p><p>CRd 作为目标寄存器的协处理器寄存器。</p><p>CRN 存放第1 个操作数的协处理器寄存器。</p><p>CRm 存放第2 个操作数的协处理器寄存器。</p><p>Opcode2 可选的协处理器特定操作码。</p></blockquote><p>ARM 处理器通过CDP 指令通知ARM 协处理器执行特定的操作。该操作由协处理器完成,即对命令的参数的解释与协处理器有关,指令的使用取决于协处理器。若协处理器不能成功地执行该操作,将产生未定义指令异常中断</p><blockquote><p>CDP p7,0,c0,c2,c3,0 ;协处理器7 操作,操作码为0,可选操作码为0</p><p>CDP p6,1,c3,c4,c5 ;协处理器操作,操作码为1</p></blockquote><h4 id="LDC-协处理器数据读取指令"><a href="#LDC-协处理器数据读取指令" class="headerlink" title="LDC 协处理器数据读取指令"></a>LDC 协处理器数据读取指令</h4><blockquote><p>LDC{cond}{L} coproc,CRd,<地址></p><p>L 可选后缀,指明是长整数传送。</p><p>coproc 指令操作的协处理器名。标准名为pn,n 为0~15</p><p>CRd 作为目标寄存的协处理器寄存器。</p><p><地址> 指定的内存地址</p></blockquote><p>LDC指令从某一连续的内存单元将数据读取到协处理器的寄存器中。协处理器数据的数据的传送,由协处理器来控传送的字数。若协处理器不能成功地执行该操作,将产生未定义指令异常中断</p><blockquote><p>LDC p5,c2,[R2,#4];读取R2+4指向的内存单元的数据,传送到协处理器p5的c2寄存器中</p><p>LDC p6,c2,[R1] ;读取是指向的内存单元的数据,传送到协处理器p6的c2 寄存器中</p></blockquote><h4 id="STC-协处理器数据写入指令"><a href="#STC-协处理器数据写入指令" class="headerlink" title="STC 协处理器数据写入指令"></a>STC 协处理器数据写入指令</h4><blockquote><p>STC{cond}{L} coproc,CRd,<地址></p><p>L 可选后缀,指明是长整数传送。</p><p>coproc 指令操作的协处理器名。标准名为pn,n 为0~15</p><p>CRd 作为目标寄存的协处理器寄存器。</p><p><地址> 指定的内存地址</p></blockquote><p>STC指令将协处理器的寄存器数据写入到某一连续的内存单元中。进行协处理器数据的数据传送,由协处理器来控制传送的字数。若协处理器不能成功地执行该操作,将产生未定义指令异常中断</p><blockquote><p>STC p5,c1,[R0]</p><p>STC p5,c1,[Ro,#-0x04]</p></blockquote><h4 id="MCR-ARM寄存器到协处理器寄存器的数据传送指令"><a href="#MCR-ARM寄存器到协处理器寄存器的数据传送指令" class="headerlink" title="MCR ARM寄存器到协处理器寄存器的数据传送指令"></a>MCR ARM寄存器到协处理器寄存器的数据传送指令</h4><blockquote><p>MCR{cond}coproc,opcodel,Rd,CRn,CRm{,opcode2}</p><p>coproc 指令操作的协处理器名。标准名为pn,n 为0~15。</p><p>cpcodel 协处理器的特定操作码。</p><p>RD 作为目标寄存器。</p><p>CRn 存放第1 个操作数的协处理器寄存器</p><p>CRm 存放第2 个操作数的协处理器寄存器。</p><p>Opcode2 可选的协处理器特定操作码。</p></blockquote><p>MCR 指令将ARM 处理器的寄存器中的数据传送到协处理器的寄存器中。若协处理器不能成功地执行该操作,将产生未定义指令异常中断</p><blockquote><p>MCR p6,2,R7,c1,c2,</p><p>MCR P7,0,R1,c3,c2,1,</p></blockquote><h4 id="MRC-协处理器寄存器到ARM寄存器到的数据传送指令"><a href="#MRC-协处理器寄存器到ARM寄存器到的数据传送指令" class="headerlink" title="MRC 协处理器寄存器到ARM寄存器到的数据传送指令"></a>MRC 协处理器寄存器到ARM寄存器到的数据传送指令</h4><blockquote><p>MRC {cond}coproc,opcodel,Rd,CRn,CRm{,opcode2}</p><p>coproc 指令操作的协处理器名。标准名为pn,n为0~15。</p><p>opcodel 协处理器的特定操作码。</p><p>Rd 作为目标寄存器。</p><p>CRn 存放第1 个操作数的协处理器寄存器。</p><p>CRm 存放第2 个操作数的协处理器寄存器。</p><p>opcode2 可选的协处理器特定操作码。</p></blockquote><p>MRC 指令将协处理器寄存器中的数据传送到ARM 处理器的寄存器中。若协处理器不能成功地执行该操作。将产生未定义异常中断</p><blockquote><p>MRC p5,2,R2,c3,c2</p><p>MRC p7,0,R0,c1,c2,1</p></blockquote><h3 id="ARM-杂项指令"><a href="#ARM-杂项指令" class="headerlink" title="ARM 杂项指令"></a>ARM 杂项指令</h3><h4 id="SWI-软中断指令"><a href="#SWI-软中断指令" class="headerlink" title="SWI 软中断指令"></a>SWI 软中断指令</h4><blockquote><p>SWI{cond} immed_24</p><p>immed_24 24 位立即数,值为0~16777215 之间的整数。</p></blockquote><p>SWI 指令用于产生软中断,从而实现在用户模式变换到管理模式,CPSR保存到管理模式的SPSR中,执行转移到SWI 向量,在其它模式下也可使用SWI 指令,处理同样地切换到管理模式</p><blockquote><p>SWI 0 ;软中断,中断立即数为0</p><p>SWI 0x123456 ;软中断,中断立即数为0x123456</p></blockquote><div class="code-wrapper"><pre><code class="hljs armasm">使用<span class="hljs-keyword">SWI</span> 指令时,通常使用以下两种方法进行传递参数,<span class="hljs-keyword">SWI</span> 异常中断处理程序就可以提供相关的服务,这两种方法均是用户软件协定。SWI异常中断处理程序要通过读取引起软中断的<span class="hljs-keyword">SWI</span> 指令,以取得<span class="hljs-number">24</span> 位立即数。 (A)指令<span class="hljs-number">24</span> 位的立即数指定了用户请求的服务类型,参数通过用寄存器传递。 <span class="hljs-keyword">MOV</span> <span class="hljs-built_in">R0</span>,<span class="hljs-number">#34</span> <span class="hljs-comment">;设置了功能号为34</span> <span class="hljs-keyword">SWI</span> <span class="hljs-number">12</span> <span class="hljs-comment">;调用12 号软中断</span> (B)指令中的<span class="hljs-number">24</span> 位立即数被忽略,用户请求的服务类型由寄存器<span class="hljs-built_in">R0</span> 的值决定,参数通过其它的通用寄存器传递。 <span class="hljs-keyword">MOV</span> <span class="hljs-built_in">R0</span>,<span class="hljs-number">#12</span> <span class="hljs-comment">;调用12 号软中断</span> <span class="hljs-keyword">MOV</span> <span class="hljs-built_in">R1</span>,<span class="hljs-number">#34</span> <span class="hljs-comment">;设置子功能号为34</span> <span class="hljs-keyword">SWI</span> <span class="hljs-number">0</span> <span class="hljs-comment">;</span>在<span class="hljs-keyword">SWI</span> 异常中断处理程序中,取出<span class="hljs-keyword">SWI</span> 立即数的步骤为:首先确定引起软中断的SWI指令是<span class="hljs-meta">ARM</span>指令还时<span class="hljs-meta">Thumb</span> 指令,这可通过对SPSR 访问得到:然后要取得该<span class="hljs-keyword">SWI</span> 指令的地址,这可通过访问<span class="hljs-built_in">LR</span> 寄存器得到:接着读出指令,分解出立即数。 读出<span class="hljs-keyword">SWI</span> 立即数: T_bit <span class="hljs-meta">EQU</span> <span class="hljs-number">0x20</span> SWI_Hander STMFD <span class="hljs-built_in">SP</span>!,{R0_R3,<span class="hljs-built_in">R12</span>,<span class="hljs-built_in">LR</span>} <span class="hljs-comment">;现场保护</span> <span class="hljs-keyword">MRS</span> <span class="hljs-built_in">R0</span>,SPSR <span class="hljs-comment">;读取SPSR</span> STMFD <span class="hljs-built_in">SP</span>!,{<span class="hljs-built_in">R0</span>} <span class="hljs-comment">;保存SPSR</span> <span class="hljs-keyword">TST</span> <span class="hljs-built_in">R0</span>,<span class="hljs-symbol">#T_bit</span> <span class="hljs-comment">;测试T标志位</span> LDRNEH <span class="hljs-built_in">R0</span>,[<span class="hljs-built_in">LR</span>,#-<span class="hljs-number">2</span>] <span class="hljs-comment">;若是Thumb指令,读取指令码(16 位)</span> <span class="hljs-keyword">BICNE</span> <span class="hljs-built_in">R0</span>,<span class="hljs-built_in">R0</span>,<span class="hljs-number">#0xFF00</span> <span class="hljs-comment">;取得Thumb 指令的8 位立即数</span> <span class="hljs-keyword">LDREQ</span> <span class="hljs-built_in">R0</span>,[<span class="hljs-built_in">LR</span>,#-<span class="hljs-number">4</span>] <span class="hljs-comment">;若是ARM 指令,读取指令码(32 位)</span> BICNQ <span class="hljs-built_in">R0</span>,<span class="hljs-built_in">R0</span>,<span class="hljs-number">#0xFF00000</span> <span class="hljs-comment">;取得ARM 指令的24 位立即数</span> … <span class="hljs-keyword">LDMFD</span> <span class="hljs-built_in">SP</span>!,{<span class="hljs-built_in">R0</span>-<span class="hljs-built_in">R3</span>,<span class="hljs-built_in">R12</span>,<span class="hljs-built_in">PC</span>}^ <span class="hljs-comment">;SWI 异常中断返回</span></code></pre></div><h3 id="MRS-读状态寄存器指令"><a href="#MRS-读状态寄存器指令" class="headerlink" title="MRS 读状态寄存器指令"></a>MRS 读状态寄存器指令</h3><blockquote><p>MRS{cond} Rd ,psr</p><p>Rd 目标寄存器。Rd 不允许为R15。</p><p>psr CPSR 或SPSR</p></blockquote><p>在ARM 处理器中,只有MRS 指令可以状态寄存器CPSR或SPSR读出到通用寄存器中</p><p>MRS 指令读取CPSR,可用来判断ALU 的状态标志,或IRQ、FIQ中断是否允许等;在异常处理程序中,读SPSR 可知道进行异常前的处理器状态等。MRS 与MSR 配合使用,实现CPSR 或SPSR 寄存器的读—修改—写操作,可用来进行处理器模式切换(),允许/禁止IRQ/FIQ中断等设置。另外,进程切换或允许异常中断嵌套时,也需要使用MRS 指令读取SPSR 状态值。保存起来</p><blockquote><p>MRS R1,CPSR ;将CPSR状态寄存器读取,保存到R1 中</p><p>MRS R2,SPSR ;将SPSR状态寄存器读取,保存到R2 中</p></blockquote><div class="code-wrapper"><pre><code class="hljs armasm">使能IRQ 中断例程: ENABLE_IRQ <span class="hljs-keyword">MRS</span> <span class="hljs-built_in">R0</span>,<span class="hljs-keyword">CPSR</span> <span class="hljs-keyword">BIC</span> <span class="hljs-built_in">R0</span>。<span class="hljs-built_in">R0</span>,<span class="hljs-number">#0x80</span> <span class="hljs-keyword">MSR</span> <span class="hljs-built_in">CPSR_c</span>,<span class="hljs-built_in">R0</span> <span class="hljs-keyword">MOV</span> <span class="hljs-built_in">PC</span>,<span class="hljs-built_in">LR</span>禁能IRQ 中断例程: DISABLE_IRQ <span class="hljs-keyword">MRS</span> <span class="hljs-built_in">R0</span>,<span class="hljs-keyword">CPSR</span> <span class="hljs-keyword">ORR</span> <span class="hljs-built_in">R0</span>,<span class="hljs-built_in">R0</span>,<span class="hljs-number">#0x80</span> <span class="hljs-keyword">MSR</span> <span class="hljs-built_in">CPSR_c</span>,<span class="hljs-built_in">R0</span> <span class="hljs-keyword">MOV</span> <span class="hljs-built_in">PC</span>,<span class="hljs-built_in">LR</span></code></pre></div><h4 id="MSR-写状态寄存器指令"><a href="#MSR-写状态寄存器指令" class="headerlink" title="MSR 写状态寄存器指令"></a>MSR 写状态寄存器指令</h4><blockquote><p>MSR{cond} psr_fields,#immed_8r</p><p>MSR{cond} psr_fields,Rm</p><p>其中: psr CPSR 或SPSR</p><p>fields 指定传送的区域。Fields 可以是以下的一种或多种(字母必须为小写):</p><p>c 控制域屏蔽字节(psr[7…0])</p><p>x 扩展域屏蔽字节(psr[15…8])</p><p>s 状态域屏蔽字节(psr[23。…16])</p><p>f 标志域屏蔽字节(psr[31…24])</p><p>immed_8r 要传送到状态寄存器指定域的立即数,8 位。</p><p>Rm 要传送到状态寄存器指定域的数据的源寄存器。</p></blockquote><p>在ARM 处理器中。只有MSR 指令可以直接设置状态寄存器CPSR或SPSR</p><blockquote><p>MSR CPSR_c,#0xD3 ;CPSR[7…0]=0xD3,即切换到管理模式。</p><p>MSR CPSR_cxsf,R3 ;CPSR=R3</p></blockquote><p>只有在特权模式下才能修改状态寄存器。<br>程序中不能通过MSR 指令直接修改CPSR 中的T 控制位来实现ARM 状态/Thumb状态的切换,必须使用BX 指令完成处理器状态的切换(因为BX 指令属转移指令,它会打断流水线状态,实现处理器状态切换)。MRS 与MSR 配合使用,实现CPSR或SPSR 寄存器的读-修改-写操作,可用来进行处理器模式切换、允许/禁止IRQ/FIQ 中断等设置。</p><div class="code-wrapper"><pre><code class="hljs armasm">堆栈指令实始化例程: INITSTACK <span class="hljs-keyword">MOV</span> <span class="hljs-built_in">R0</span>,<span class="hljs-built_in">LR</span> <span class="hljs-comment">;保存返回地址</span> <span class="hljs-comment">;设置管理模式堆栈</span> <span class="hljs-keyword">MSR</span> <span class="hljs-built_in">CPSR_c</span>,<span class="hljs-number">#0xD3</span> <span class="hljs-keyword">LDR</span> <span class="hljs-built_in">SP</span>,StackSvc <span class="hljs-comment">;设置中断模式堆栈</span> <span class="hljs-keyword">MSR</span> <span class="hljs-built_in">CPSR_c</span>,<span class="hljs-number">#0xD2</span> <span class="hljs-keyword">LDR</span> <span class="hljs-built_in">SP</span>,StackIrq</code></pre></div><h3 id="ARM-伪指令"><a href="#ARM-伪指令" class="headerlink" title="ARM 伪指令"></a>ARM 伪指令</h3><h4 id="ADR-小范围的地址读取伪指令"><a href="#ADR-小范围的地址读取伪指令" class="headerlink" title="ADR 小范围的地址读取伪指令"></a>ADR 小范围的地址读取伪指令</h4><blockquote><p>ADR{cond} register,exper</p><p>register 加载的目标寄存器。</p><p>exper 地址表达式。当地址值是非字地齐时,取值范围-255~255 字节之间;当地址是字对齐时,取值范围-1020~1020字节之间。 </p><p>对于基于PC 相对偏移的地址值时,给定范围是相对当前指令地址后两个字处(因为ARM7TDMI为三级流水线)。</p></blockquote><p>ADR 指令将基于PC 相对偏移的地址值读取到寄存器中。在汇编编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD 指令或SUB 指令来实现该ADR 伪指令的功能,若不能用一条指令实现,则产生错误,编译失败</p><blockquote><p>LOOP MOV R1, #0xF0</p><p>…</p><p>ADR R2, LOOP ;将LOOP 的地址放入R2</p><p>ADR R3, LOOP+4</p><p>可以用ADR 加载地址,实现查表:</p><p>…</p><p>ADR R0,DISP_TAB ;加载转换表地址</p><p>LDRB R1,[R0,R2] ;使用R2作为参数,进行查表</p><p>…</p><p>DISP_TAB</p><p>DCB0Xc0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90</p></blockquote><h4 id="ADRL-中等范围的地址读取伪指令"><a href="#ADRL-中等范围的地址读取伪指令" class="headerlink" title="ADRL 中等范围的地址读取伪指令"></a>ADRL 中等范围的地址读取伪指令</h4><blockquote><p>ADR{cond} register,exper</p><p>register 加载的目标寄存器。</p><p>expr 地址表达式。当地址值是非字对齐时,取范围-64K~64K 字节之间;当地址值是字对齐时,取值范围-256K~256K字节之间。</p></blockquote><p>ADRL 指令将基于PC 相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中,比ADR伪指令可以读取更大范围的地址。在汇编编译源程序时,ADRL 伪指令被编译器替换成两个条合适的指令。若不能用两条指令实现ADRL 伪指令功能,则产生错误,编译失败</p><blockquote><p>ADRL R0,DATA_BUF</p><p>…</p><p>ADRL R1 DATA_BUF+80</p><p>…</p><p>DATA_BUF</p><p>SPACE 100 ;定义100 字节缓冲区</p><p>可以且用ADRL 加载地址,实现程序跳转,中等范围地址的加载:<br>…</p><p>ADR LR,RETURNI ;设置返回地址</p><p>ADRL R1Thumb_Sub+1 ;取得了Thumb 子程序入口地址,且R1 的0 位置1</p><p>BX R1 ;调用Thumb子程序,并切换处理器状态</p><p>RETURNI</p><p>…</p><p>CODE16</p><p>Thumb_Sub</p><p>MOV R1,#10</p><p>…</p></blockquote><h4 id="LDR-大范围的地址读取伪指令"><a href="#LDR-大范围的地址读取伪指令" class="headerlink" title="LDR 大范围的地址读取伪指令"></a>LDR 大范围的地址读取伪指令</h4><blockquote><p>LDR{cond} register,=expr/label_expr</p><p>register 加载的目标寄存器</p><p>expr 32 位立即数。</p><p>label_expr 基于PC 的地址表达式或外部表达式。</p></blockquote><p>LDR 伪指令用于加载32 位的立即数或一个地址值到指定寄存器。在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。若加载的常数未超出MOV 或MVN 的范围,则使用MOV 或MVN 指令代替该LDR 伪指令,否则汇编器将常量放入字池,并使用一条程序相对偏移的LDR指令从文字池读出常量</p><blockquote><p>LDR R0,=0x123456 ;加载32 位立即数0x12345678</p><p>LDR R0,=DATA_BUF+60 ;加载DATA_BUF 地址+60</p><p>…</p><p>LTORG ;声明文字池</p><p>伪指令LDR 常用于加载芯片外围功能部件的寄存器地址(32 位立即数),以实现各种控制操作加载32位立即数:</p><p>…</p><p>LDR R0,=IOPIN ;加载GPIO 寄存器IOPIN 的地址</p><p>LDR R1,[R0] ;读取IOPIN 寄存器的值</p><p>…</p><p>LDR R0,=IOSET</p><p>LDR R1,=0x00500500</p><p>STR R1,[R0] ;IOSET=0x00500500</p><p>…</p><p>从PC 到文字池的偏移量必须小于4KB。与ARM 指令的LDR 相比,伪指令的LDR的参数有“=”号</p></blockquote><h4 id="NOP-空操作伪指令"><a href="#NOP-空操作伪指令" class="headerlink" title="NOP 空操作伪指令"></a>NOP 空操作伪指令</h4><p>NOP 伪指令在汇编时将会被代替成ARM 中的空操作,比如可能为“MOV R0, R0”指令等</p><blockquote><p>使用就单NOP</p></blockquote><h3 id="ARM寻址"><a href="#ARM寻址" class="headerlink" title="ARM寻址"></a>ARM寻址</h3><h4 id="立即数寻址"><a href="#立即数寻址" class="headerlink" title="立即数寻址"></a>立即数寻址</h4><p>立即数前面有“#”号,并且如果是十六进制数则在“#”后添加“0x”或“&”,二进制数“#”后面加“%”</p><h4 id="寄存器间接寻址"><a href="#寄存器间接寻址" class="headerlink" title="寄存器间接寻址"></a>寄存器间接寻址</h4><p>操作数的地址在寄存器中 </p><p>ADD R0,R1,[R2]</p><h4 id="基址变址寻址"><a href="#基址变址寻址" class="headerlink" title="基址变址寻址"></a>基址变址寻址</h4><p>将寄存器的内容与指令中给出的地址偏移量相加,从而得到一个操作数的有效地址</p><p>ADD R0,R1,[R2]</p><h4 id="多寄存器寻址"><a href="#多寄存器寻址" class="headerlink" title="多寄存器寻址"></a>多寄存器寻址</h4><p>一条指令可以完成多个寄存器值得传递,一条指令传送最多16个通用寄存器的值</p><p>LDMIA R0,{R1,R2,R3,R4}</p><h4 id="相对寻址"><a href="#相对寻址" class="headerlink" title="相对寻址"></a>相对寻址</h4><p>以程序计数器PC的值作为基地址,指令中的地址标号作为偏移量,将两者相加后得到的操作数的有效地址</p><p>例如:BL NEXT</p><h3 id="ARM堆栈的增长方式"><a href="#ARM堆栈的增长方式" class="headerlink" title="ARM堆栈的增长方式"></a>ARM堆栈的增长方式</h3><p>当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(FullStack)</p><p>当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(FullStack)</p><p>递增堆栈:向高地址方向生长</p><p>递减堆栈:向低地址方向生长</p>]]></content>
<categories>
<category>逆向</category>
</categories>
</entry>
<entry>
<title>MIPS栈溢出原理</title>
<link href="/article/bd2e4070.html"/>
<url>/article/bd2e4070.html</url>
<content type="html"><![CDATA[<h1 id="MIPS的函数调用"><a href="#MIPS的函数调用" class="headerlink" title="MIPS的函数调用"></a>MIPS的函数调用</h1><p>小知识:</p><blockquote><p>Mips 调用函数时不会将返回地址放入栈中,而在非叶子函数中,为了调用下一个函数,会将上一个函数的返回地址压栈</p><p>叶子函数,即该函数中不会调用任何其他函数</p><p>非叶子函数,即该函数需要调用其他函数</p></blockquote><p>mips的函数调用过程</p><p>当函数A执行到调用函数B的指令时,函数调用指令复制当前pc寄存器的值到ra寄存器中,即ra中存放返回地址</p><blockquote><p>他这个没有专门的控制ra的指令,在ja指令执行的时候,给ra赋值了</p></blockquote><p>程序跳转到函数B的时候,如果是非叶子函数,函数B会先把函数A的返回地址压栈(即ra寄存器的值压栈),叶子函数没有这个操作,返回地址就只存在于ra寄存器中</p><blockquote><p>main函数一般是一个非叶子函数,我们几乎可以在任何mian开头看到 <code>sw $ra,0x20+var_s4($sp)</code>这条指令</p></blockquote><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141121629.png" alt="image-20220402141121629"></p><p>函数B执行完之后,叶子函数直接使用<code>jr $ra</code>指令返回函数A,而非叶子函数则需要,从堆栈中取出返回地址,然后将返回地址放入ra寄存器,再使用<code>jr $ra</code>指令</p><h2 id="下面是两个程序(叶子和非叶子)的分析"><a href="#下面是两个程序(叶子和非叶子)的分析" class="headerlink" title="下面是两个程序(叶子和非叶子)的分析"></a>下面是两个程序(叶子和非叶子)的分析</h2><h3 id="叶子函数"><a href="#叶子函数" class="headerlink" title="叶子函数"></a>叶子函数</h3><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141131544.png" alt="image-20220402141131544"></p><p>这个程序中,add函数为叶子函数,我们去分析add函数调用之前做了什么。</p><blockquote><p>这里使用<code>mipsel-linux-gnu-gcc -o tree tree.c -static</code>进行编译</p><p>然后使用<code>qemu-mipsel -g 1234 tree</code>与ida连用的动态调试</p><p>IDA remote另一篇文章会详细讲,这里就不赘述</p></blockquote><p>下断点到main函数,能看到在<code>400578</code>处有看到将ra压栈的操作,这个就是操作系统的某个地址。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141137056.png" alt="image-20220402141137056"></p><p>重点在<code>0040059c</code>这个行,调用add函数,先不关心参数调用,只看ra寄存器的相关操作</p><p>执行完00400578后,寄存器以及栈中的内容</p><p><img src="/../../../Library/Application%20Support/typora-user-images/image-20210825095723949.png" alt="image-20210825095723949"></p><p>继续执行至0040059c,此时ra值没有改变</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141148995.png" alt="image-20220402141148995"></p><p>执行jal add</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141156455.png" alt="image-20220402141156455"></p><p>跳转过来之后,ra的值变了,值正好是jr add的下一条可用指令(nop的目的只是为了对齐)</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141203617.png" alt="image-20220402141203617"></p><p>再看add的所有指令,会发现,只有跳回main函数指令出现了ra寄存器</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141210131.png" alt="image-20220402141210131"></p><h3 id="非叶子函数"><a href="#非叶子函数" class="headerlink" title="非叶子函数"></a>非叶子函数</h3><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141216124.png" alt="image-20220402141216124"></p><p>add中调用了printf()函数。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141223617.png" alt="image-20220402141223617"></p><p>执行进入add函数,与叶子函数相同</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141230705.png" alt="image-20220402141230705"></p><p>进入之后,抬高堆栈后,执行了ra压栈操作,即<code>00400544</code>这一行的操作</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141238248.png" alt="image-20220402141238248"></p><p>上图是函数执行完之后,准备返回main,在<code>0040059c</code>这行把main函数的返回地址放回ra。</p><p>然后通过<code>jr $ra</code>返回main。</p><h2 id="参数"><a href="#参数" class="headerlink" title="参数"></a>参数</h2><p>mips函数调用传递参数规则,前四个参数通过$a1- $a3寄存器传递,其他参数通过栈传递。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141246086.png" alt="image-20220402141246086"></p><p>从main函数中来看,先将参数数字放到临时栈中(蓝色框中),然后将第五个参数去取出,放入add的栈中,然后将前四个栈放到a0-a3寄存器中(红框)</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141304900.png" alt="image-20220402141304900"></p><p>我们来尝试画出其栈图,下图是main函数的栈图</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141314906.png" alt="image-20220402141314906"></p><p>红框为上个函数的返回地址,蓝框为局部变量,绿的是第五个参数。</p><h1 id="栈溢出"><a href="#栈溢出" class="headerlink" title="栈溢出"></a>栈溢出</h1><p>我们使用下面代码来做实验</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141342106.png" alt="image-20220402141342106"></p><p>代码大意就是从passwd这个文件读取文件。</p><p>尝试使用大量字符串</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141349030.png" alt="image-20220402141349030"></p><p>运行发现报错</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141355070.png" alt="image-20220402141355070"></p><p>栈溢出的目的是覆盖返回地址,上面说过,main一般是一个典型的非叶子函数,而且passwd文件的读取是在main中执行的,</p><p>所以我们目标应该在main刚进来的ra位置,使用ida+qemuGdb调试。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141401755.png" alt="image-20220402141401755"></p><p>运行至main</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141409333.png" alt="image-20220402141409333"></p><p>并且关注ra的值存放的位置,右键 -> jump a new window</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141418631.png" alt="image-20220402141418631"></p><p>执行完ra压栈之后,栈中的数据</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141427263.png" alt="image-20220402141427263"></p><p>下面让程序读完passwd文件,这个地方有个小方法,读取一般是在循环中一个字符一个字符读的,所以向下单步执行,如果遇到多次循环,就可以尝试吧断点下载循环执行完的下一行。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141436143.png" alt="image-20220402141436143"></p><p>上图发现循环,尝试在循环外下断,不要断在nop上,情况允许就尽量断在nop下一行</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141447106.png" alt="image-20220402141447106"></p><p>ida下使用f9可以继续运行,直到下一个断点,运行到<code>00400500</code>后可以看到,地址存放的地方已经被覆盖</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141454519.png" alt="image-20220402141454519"></p><p>接下来可以使用cyclic等工具来计算长度,编写poc或exp利用。</p>]]></content>
<categories>
<category>逆向</category>
</categories>
</entry>
<entry>
<title>MIPS指令集</title>
<link href="/article/6a1d16f9.html"/>
<url>/article/6a1d16f9.html</url>
<content type="html"><![CDATA[<h1 id="MIPS指令集"><a href="#MIPS指令集" class="headerlink" title="MIPS指令集"></a>MIPS指令集</h1><p>mips (risc 精简指令集)</p><h2 id="寄存器"><a href="#寄存器" class="headerlink" title="寄存器"></a>寄存器</h2><p>mips 有32个寄存器,编号是从$0到$31</p><p>没有强制规则,但约定用法还是引入了一堆约定名</p><p>尽量使用约定名或者叫助记符</p><p>下面是寄存器用法(截的scdn [En Takahashi]老哥的),这些东西不一定要记,尽量还是用到多查,时间久了也就记住了</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141050555.png" alt="image-20220402141050555"></p><p>比较特殊的是</p><p>$0号寄存器,他里边放的只有0,又叫0号寄存器</p><p>$31号寄存器,里边放的是函数调用指令的返回地址</p><p>$1号寄存器,又叫at,由编译器生成的复合指令使用</p><blockquote><p>d</p></blockquote><p>v0,v1不够用的话用内存</p><p>hi和lo是两个跟乘法相关的寄存器,不是通用寄存器,所以不能用在其他地方</p><h2 id="寻址"><a href="#寻址" class="headerlink" title="寻址"></a>寻址</h2><p>寻址方式为地址 = <code>基地址+偏移</code></p><h2 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h2><p>c中 long int short char</p><p>mips dword word halfword byte</p><p>长度 8 4 2 1</p><h2 id="指令"><a href="#指令" class="headerlink" title="指令"></a>指令</h2><p>mips所有指令都是32位的</p><p>mips指令分为三种格式</p><ol><li>R-format 其他所有的</li><li>I-format 有立即数的指令</li><li>J-format 无条件跳转</li></ol><h3 id="R-format"><a href="#R-format" class="headerlink" title="R-format"></a>R-format</h3><p>对非立即数和跳转的操作</p><p>例如:add $8, $17, $18 =》 $18 = $8+$17 </p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141057353.png" alt="image-20220402141057353"></p><h3 id="I-format"><a href="#I-format" class="headerlink" title="I-format"></a>I-format</h3><p>数据放到寄存器,或者放入地址</p><p>分支(判断)指令</p><p>立即数运算</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141102389.png" alt="image-20220402141102389"></p><h3 id="J-format"><a href="#J-format" class="headerlink" title="J-format"></a>J-format</h3><p>跳转,类似于jump</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141108000.png" alt="image-20220402141108000"></p><h2 id="常用汇编指令"><a href="#常用汇编指令" class="headerlink" title="常用汇编指令"></a>常用汇编指令</h2><p>上边指令分类其实只是一个理解,详细的看下边</p><p><strong>lb / lh / lw</strong> : 从存储器中读取一个byte/half word/word的数据到寄存器中</p><p><strong>sb / sh /sw</strong>: 把一个byte/half word/word的数据从寄存器存储到存储器中</p><p><strong>mov / movz / movn</strong>: 复制,n为负,z为零。mov $1,$2; movz $1,$2,$3($3为零则复制$2到$1)</p><p><strong>addi/addiu</strong>: 把一个寄存器的内容加上一个立即数;u为不带符号加。 rd = rs + im</p><p><strong>sub/subu</strong>: 把两个定点寄存器的内容相减。 rd = rs - rt</p><p><strong>div/divu</strong>: 两个定点寄存器的内容相除。 </p><p><strong>mul/mulu</strong>: 两个定点寄存器的内容相乘。 </p><p><strong>slt/slti/sltui</strong>: 如果rs的值小于rt,那么设置rd的值为1,否则设置rd的值为0。 rd = (rs < rt) ? 1 : 0 ; rd = (rs < im) ? 1 : 0</p><p><strong>and/andi:</strong> 与运算,两个寄存器中的内容相与 ;i为立即数。 rd = rs & rt ; rd = rs & im</p><p><strong>or/ori</strong>: 或运算。 rd = rs | rt ; rd = rs | im</p><p><strong>xor/xori</strong>: 异或运算。 rd = rs ^ rt ;rd = rs ^ im</p><p><strong>nor/nori:</strong> 取反运算。 rd = !(rs | rt)</p><p><strong>j/jr/jal/jalr</strong>: j直接跳转 PC = { (PC+4) [31,28] , addr, 00};jr使用寄存器跳转 PC = rs; jal $31 = PC;PC = {(PC+4) [31,28],addr,00}</p><p><strong>beq/beqz/benz/bne</strong>: 条件转移eq相等,z零,ne不等。 beq , PC = (rs == rt) ? PC+4+im << 2 : PC ; bne , PC = (rs != rt) ? PC+4+im << 2 : PC </p><p><strong>lui</strong>: 把一个16位的立即数填入到寄存器的高16位,低16位补零。 rt = im * 65536(2^16)</p><p><strong>lw</strong>: rt = memory[ rs + im]</p><p><strong>sw</strong>: memory[ rs + im] = rt</p><p><strong>sll/srl</strong>: 逻辑左移/右移。 rd = rs << shamt ; rd = rs >> shamt </p>]]></content>
<categories>
<category>逆向</category>
</categories>
</entry>
<entry>
<title>一个c语言代码变为c语言程序的全过程</title>
<link href="/article/5aedeb05.html"/>
<url>/article/5aedeb05.html</url>
<content type="html"><![CDATA[<div class="code-wrapper"><pre><code class="hljs c"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdio.h></span></span><span class="hljs-type">int</span> <span class="hljs-title function_">main</span><span class="hljs-params">(<span class="hljs-type">int</span> argc, <span class="hljs-type">char</span> <span class="hljs-type">const</span> *argv[])</span>{ <span class="hljs-built_in">printf</span>(<span class="hljs-string">"hello world\n"</span>); <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;}</code></pre></div><p>这样一段代码通过编译器进行如下操作后来得到可执行文件</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140948521.png" alt="image-20220402140948521"></p><p>下面详细说明下每个步骤</p><h1 id="预处理"><a href="#预处理" class="headerlink" title="预处理"></a>预处理</h1><p>根据<code>#</code>开头的命令,将头文件命令行代码插入代码</p><p>可以用gcc -E hello.c -o hello.i 来只完成预处理</p><p>打开hello.i 可以发现代码前边多处500多行代码</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140956951.png" alt="image-20220402140956951"></p><p>这个可以在本机目录下找到stdio.h这个文件</p><p>这就是预处理的整个过程</p><h1 id="编译"><a href="#编译" class="headerlink" title="编译"></a>编译</h1><p>将hello.i编译成汇编语言,这个过程之后程序会更接近机器语言</p><blockquote><p>这里解释下什么是机器语言,什么是高级语言</p><p>我们定义 00100 1 0的含义为1 + 0 即 00100 为加号 1 为被加数 0 为加数</p><p>这样写偏向于底层,在程序员看来是非常不直接的,不方便的。(这种二进制代码也被称为硬编码)</p><p>那我们再次规定,我们用add 1 0 来表示1 + 0,这样子容易理解多了,</p><p>(类似于早期这种比较简单语言称为汇编语言,这样的代码需要巨大的代码量来完成一些简单的逻辑)</p><p>人们使用汇编语言将常用的一些逻辑二次封装成为比较人性化的代码</p><p>再把 add 1 0 二次封装,为 1 + 0 这样,就很方便使用和理解</p><p>(这种代码就被称为高级语言,这种语言更符合人类的使用习惯)</p><p>上面这串代码从下往上的过程,就被称为代码的编译,处理它们的软件被称为编译器</p></blockquote><p>使用 gcc -S hello.i -o hello.s可以将预处理后的文件编译为汇编语言的文件</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141005753.png" alt="image-20220402141005753"></p><h1 id="汇编"><a href="#汇编" class="headerlink" title="汇编"></a>汇编</h1><p>将hello.s 打包成<code>可重定位目标程序</code> hello.o</p><p>这一步已经将机器语言变成了二进制文件,用文本文件打开后会看到乱码</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141013182.png" alt="image-20220402141013182"></p><p>但仍然可以用二进制文本编辑器查看</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141021358.png" alt="image-20220402141021358"></p><h1 id="链接"><a href="#链接" class="headerlink" title="链接"></a>链接</h1><p>我们上边说过,早期人们将一些常用的逻辑打包,</p><p>一些常用逻辑包放在在标准库,使大家不需要每个函数都存放在代码里</p><p>就比如我们使用的printf 函数在标准库中的printf.o文件</p><p>在链接时,将hello.o 和printf.o两个文件打包成可执行文件</p><p>使用 gcc hello.o -o hello 就可以链接需要的文件得到可执行文件</p>]]></content>
<categories>
<category>逆向</category>
</categories>
</entry>
<entry>
<title>老去的尼尼卡 --英雄的迟暮</title>
<link href="/article/f8245e93.html"/>
<url>/article/f8245e93.html</url>
<content type="html"><![CDATA[<h2 id="老去的尼尼卡"><a href="#老去的尼尼卡" class="headerlink" title="老去的尼尼卡"></a>老去的尼尼卡</h2><p>我们的尼尼卡老去了, </p><p>他伟岸的肩膀不再挺拔…… </p><p>这位满头白发的老人</p><p>真的曾经拥有钢铁一般的力量? </p><p>啊,母亲啊!</p><p>到底有多少次他挥舞着“土狼”镰刀, </p><p>袒胸露背,</p><p>在麦田的尽头突然大声地咆哮。 </p><p>他肯定搬移过大山 把它们并排而列, </p><p>他那滴汗的脸上 喷射着火焰和浓烟。 </p><p>可他现在连膝盖都动不了,</p><p>岁月割去了它们。 </p><p>他只能躺下,</p><p>或者做梦,</p><p>或者告诉他子孙的子孙 </p><p>他曾经的过往。 </p><p>他偶尔会听见 </p><p>附近麦田传来的歌声, </p><p>他那曾经坚硬的心开始愉悦地跳动。 </p><p>他颤抖地走出了门。 </p><p>他拄着拐杖往前走了几步。 </p><p>当他看到年轻的小伙, </p><p>他安慰地笑了起来。 </p><p>——索塞罗</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402140855691.png" alt="image-20220402140855691"></p>]]></content>
<categories>
<category>诗</category>
</categories>
</entry>
<entry>
<title>一个安卓锁机软件的逆向分析</title>
<link href="/article/e48e684a.html"/>
<url>/article/e48e684a.html</url>
<content type="html"><![CDATA[<p>前两天在吾爱上看到有人求助手机被锁,顺手吧样本下载了,分析下。</p><p>样本桌面是一个百度网盘的图标</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141506388.png" alt="image-20220402141506388"></p><p>这像素一看就是假的。。。</p><p>打开后是个root锁机,这里还是提醒各位没事不要随便开root权限,这都2021年了,还有这种垃圾软件,也是服了!</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141514360.png" alt="image-20220402141514360"></p><p>直接jeb</p><p>启动后看到这变量名是真恶心啊!!!</p><p>发现MainActivity中只调用了一个hh</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141521365.png" alt="image-20220402141521365"></p><h2 id="第一个页面"><a href="#第一个页面" class="headerlink" title="第一个页面"></a>第一个页面</h2><p>这里发现第一个页面是第四层函数</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141530861.png" alt="image-20220402141530861"></p><p>这里主要是q()中是个文字编码,提取出来,把这两行解密下。</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141538590.png" alt="image-20220402141538590"></p><p>这里有一行解码后发现是一个网站,猜测可能是访问网站返回解码</p><p>100000005线程处跟进</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141544779.png" alt="image-20220402141544779"></p><p>本质是做了一个判断,继续跟进isINTERET()</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141552826.png" alt="image-20220402141552826"></p><p>这里发现9160,尝试下,对了</p><p>然后进入第二个页面</p><p>(还是多重锁机骗钱,可以很骚,很傻逼)</p><h2 id="第二个页面"><a href="#第二个页面" class="headerlink" title="第二个页面"></a>第二个页面</h2><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141602192.png" alt="image-20220402141602192"></p><p>第二层是第五层的函数</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141609649.png" alt="image-20220402141609649"></p><p>跟进100000008</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141617211.png" alt="image-20220402141617211"></p><p>点击屏幕30次会出现两个控件</p><p>然后跟进100000009</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141624353.png" alt="image-20220402141624353"></p><p>这里try里边先做了一个字符编码,直接把m这个函数摘下来稍作修改</p><p>解码后是9,5,10</p><p>然后通过这三个数做了运算</p><p>同样吧加密摘下来</p><p>这个加密处理处v0.val$test 是界面给的序列号</p><p>这个序列号是通过取随机数然后通过m下的方法处理后的(这个软件变量方法名太恶心了,就在第五层的倒数第三行)</p><p>还是老办法,把这个函数取出来处理下</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141631663.png" alt="image-20220402141631663"></p><p>把v1,v2 的值交换下就可以了</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141638554.png" alt="image-20220402141638554"></p><p>转第二层锁</p><h2 id="第三个页面"><a href="#第三个页面" class="headerlink" title="第三个页面"></a>第三个页面</h2><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141647476.png" alt="image-20220402141647476"></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141654580.png" alt="image-20220402141654580"></p><p>这个和上一个差不多做法就不细说了</p><p>把改过的函数挂出来吧(这里边函数或者变量名是修改过的,后边会把整个项目脚本放上来,可以看那个)</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141702375.png" alt="image-20220402141702375"></p><p>解出来后跳到第四个页面</p><h2 id="第四个页面"><a href="#第四个页面" class="headerlink" title="第四个页面"></a>第四个页面</h2><p>第三层函数</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141710260.png" alt="image-20220402141710260"></p><p>和上边也是差不多</p><p>继续改函数</p><p>这里要注意 粉红兔 这个实例在创建的时候传了个 fuck参数(当时找了好久,好烦呀)</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141718598.png" alt="image-20220402141718598"></p><p><img src="https://i.loli.net/2021/05/28/njByRldAL7HgmqP.png" alt="image-20210528183252244"></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141726058.png" alt="image-20220402141726058"></p><p>搞定,下一层下一层</p><h2 id="第五个页面"><a href="#第五个页面" class="headerlink" title="第五个页面"></a>第五个页面</h2><p>第一层函数,看起来也差不多</p><p>看第四个页面,不过这里又个迷惑人的点</p><p>随机码多了一个b,解码时删掉这个解就好</p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141734543.png" alt="image-20220402141734543"></p><p><img src="https://fastly.jsdelivr.net/gh/p1yang/image@main/image-20220402141741322.png" alt="image-20220402141741322"></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>没有什么特别奇怪的算法,都是大差不差,刚去看了下吾爱,好像有师傅提前解出来了</p><p>网站也是被挺多人留言了</p><p>分析的时候去找过那个qq群,好像还在运行,这种人就挺可恶的</p><p>拿技术做坏事,为人所不齿</p><p>脚本因为是分析的时候写的,乱得很,这里先放上来</p><p><a href="https://gitee.com/p1piyang/backward-analysis/tree/master">https://gitee.com/p1piyang/backward-analysis/tree/master</a></p><p>累死了!!!</p>]]></content>
<categories>
<category>逆向</category>
</categories>
</entry>
<entry>
<title>致橡树</title>
<link href="/article/26be181c.html"/>
<url>/article/26be181c.html</url>
<content type="html"><![CDATA[<h1 id="致橡树"><a href="#致橡树" class="headerlink" title="致橡树"></a>致橡树</h1><p> 舒婷</p><p>我如果爱你——<br>绝不像攀援的凌霄花,<br>借你的高枝炫耀自己;<br>我如果爱你——<br>绝不学痴情的鸟儿,<br>为绿荫重复单调的歌曲;<br>也不止像泉源,<br>常年送来清凉的慰藉;<br>也不止像险峰,<br>增加你的高度,衬托你的威仪。<br>甚至日光,<br>甚至春雨。</p><p>不,这些都还不够!<br>我必须是你近旁的一株木棉,<br>作为树的形象和你站在一起。<br>根,紧握在地下;<br>叶,相触在云里。<br>每一阵风过,<br>我们都互相致意,<br>但没有人,<br>听懂我们的言语。<br>你有你的铜枝铁干,<br>像刀,像剑,也像戟;<br>我有我红硕的花朵,<br>像沉重的叹息,<br>又像英勇的火炬。</p><p>我们分担寒潮、风雷、霹雳;<br>我们共享雾霭、流岚、虹霓。<br>仿佛永远分离,<br>却又终身相依。<br>这才是伟大的爱情,<br>坚贞就在这里:<br>爱——<br>不仅爱你伟岸的身躯,<br>也爱你坚持的位置,<br>足下的土地。</p>]]></content>
<categories>
<category>诗</category>
</categories>
</entry>
</search>