网络安全逆向分析之rust逆向技巧
rust逆向技巧
rust逆向三板斧:
- 快速定位关键函数 (真正的main函数):观察输出、输入,字符串搜索,断点等方法。
- 定位关键 加密区 :根据输入的flag,打硬件断点,快速捕获程序中对flag访问的位置(加密区)。
- 定位错误输出(附近一定有比较功能的程序):定位到比较位置后 提取出正确加密后的结果 。
1:一个函数在 被调试运行(F8) 之后,如果既有输出,又要我们输入,那么我们当前所在的函数肯定不是真正的main函t数。
2:所以存在flag(无论加密前后)的内存区域,都要首先打上硬件读断点 。
3:在c语言层面,对临时变量、局部变量等的修改,在汇编层面一定会反映到对内存空间的修改上。
rust语言的传参、返回值
- 前6个参数分别使用di,si,dx,cx,r8,r9,返回值使用ax寄存器:
go语言的传参、返回值
- 前6个参数,ax,bx,cx,di,si,r8,r9,r10,r11返回值 ax:
例题1:
题目:ciscn2024 rust_baby
定位关键函数 --- main函数
- 先运行观察输出的错误字符串:
- 但是在ida中搜索不到,所以只能调试来快速定位关键输入、输出函数:
现在入口函数打上断点:
这个函数位置出现了输出,在这里下断点,后面步入进入该函数继续调试定位:
调用了外面传入给rcx参数这个地址处的函数,该函数也有输出,继续步入:
直到进入rcx这个函数,才捕获到了输出 where is your flag?: 的函数,且这里任然可以继续往下调试 ,而没有停止来让我们输入,说明sub_7FF6BC37C570这个函数大概率就是单纯的输出函数:
- 后面在定位到输入的位置,肯定在这个输出函数的后面,如果不在说明当前函数不是真正的main,还需要继续步入:
单步直到这里,就停止下来,需要我们输入:
- 根据上面定位输入、输出,可以基本确定rcx这个函数就是真正的main函数。
定位flag的加密区
- 输入flag后,在flag的内存区打上硬件读断点,后面程序访问flag内存区时就会停止:
这里打断点,然后F9继续执行:
后续ida触发硬件读断点,这里大概率就是flag的加密区:
- 分析伪代码、或者直接分析汇编代码,理清加密逻辑即可。这里将flag 8个字符(不够就用'E'填充),一组进入encode加密,出来后再异或0x33,最后放入到encode2_flag中:
- encode函数加密分析,将加密再输入可以看到他不是一个对称加密,可以直接排除纯异或的加密方式(对称加密):
根据函数加密前后的结果,来开始推断加密方式(输入的字符串要有特点,会更容易看出来):
输入 bbbbbbbb encode加密后 aabbccdd ,可以看出只是对字符进行简单的前后移位处理,可以多测试几组数据来中和判断。
符合前面推断 ==> key_1 = [1,1,0,0,-1,-1,-2,-2] ,对字符的ASCII码进行加减操作。
继续定位下一个加密区:
- 输入的flag加密后在内存中的位置已经改变,所以前面的硬件断点后续没用,再在新的flag位置打上断点:
继续执行F9,ida再次触发硬件断点,定位到下一个flag加密区:
这里对加密后的flag进行访问,可能也是一个加密区:
- 继续分析伪代码、或者汇编:
这里只是将前面加密后的flag(encode2_flag),16个一组一共7轮,与一个key的数组进行异或,所以需要提取出这个key数组。首先确定这个key数组 是不是静态的 (与flag的长度、内容都无关),如果是静态的就能直接从内存中提取出来。
这里可以通过 输入不同的flag(内容不同、长度不同),来比较程序的key数组是否相同:
先根据输入不同的flag,来比较第一轮的key:
可以看到即使输入不同的flag,第一轮加密的key数组都是相同的,所以直接调试来从内存中提取出key数组,一共有7轮。
- 如果是动态的数组(与flag的输入相关),则另外分析。
继续定位下一个加密区:
- 同样再给第二次加密后的flag内存区打上硬件断点
然后继续F9运行,再次触发硬件断点,所以这里也可能是一个加密区:
- 分析伪代码、汇编代码:
这个do_while循环中,并没有加密的成分,只是对flag做一个复值操作,换到另外一片内存区域:
最后将两次加密后的flag全家转移到了另外一篇内存区域,并没有加密操作,所以这里不是加密区 ,但是还要在这里下一个硬件断点,因为保不准后面可以使用这片区域的flag再进行加密操作。
- 上面断点后继续执行F9,这里又触发ida的额硬件断点:
- 继续分析这里的伪代码、或者汇编代码,可以发现是base64加密,加密的表如下:
- base64加密完成后,又换了一个内存区域来存储:
继续打上硬件断点后运行 F9,但是这次触发硬件断点也没有加密操作 和 内存区转换的操作,应该是单纯的检查而已:
- 最后在 base64加密后的内存区域 下断点,其他的断点都删除掉:
然后在这里又触发了硬件断点:
仔细观察可以发现这是一个比较的区域,后面的 错误输出也紧挨比较区 ,这里比较,输入的flag加密后 和 正确的flag加密后的结果:
解密
- 最后根据分析的加密,和提取出来的数据,逆向出flag:
res = "igdydo19TVE13ogW1AT5DgjPzHwPDQle1X7kS8TzHK8S5KCu9mnJ0uCnAQ4aV3CSYUl6QycpibWSLmqm2y/GqW6PNJBZ/C2RZuu+DfQFCxvLGHT5goG8BNl1ji2XB3x9GMg9T8Clatc="# 分组异或
key = [0xDC, 0x5F, 0x20, 0x22, 0xC2, 0x79, 0x19, 0x56, 0x35, 0xDA, 0x8B, 0x47, 0xD3, 0x19, 0xFC, 0x55,0x14, 0xCD, 0xD2, 0x7B, 0x58, 0x59, 0x09, 0x42, 0xDE, 0x2C, 0xB4, 0x48, 0xD9, 0xF2, 0x1B, 0xA9,0x40, 0xE1, 0xA6, 0xFB, 0xFF, 0x38, 0xC1, 0xD5, 0xE2, 0xE8, 0x77, 0x78, 0x6F, 0x22, 0x04, 0xE6,0x16, 0x3E, 0x0C, 0x35, 0x52, 0x5C, 0xFD, 0xC1, 0xE5, 0x59, 0x1C, 0xD0, 0xAE, 0x5A, 0xB2, 0xDD,0x19, 0xF8, 0x42, 0xE6, 0x2C, 0x89, 0x59, 0xE5, 0x11, 0x9C, 0xC8, 0x7B, 0x81, 0x70, 0x7F, 0x6F,0xBC, 0x6F, 0x02, 0x8F, 0xF7, 0xF4, 0xC8, 0x70, 0xAE, 0x02, 0xF8, 0x5B, 0xE2, 0x72, 0x08, 0x09,0x6F, 0xBF, 0x4B, 0x39, 0xB5, 0xD0, 0x1E, 0xA3, 0x23, 0xAB, 0x9B, 0x43, 0xB1, 0x15, 0xD7, 0xBE]table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"# base64解码后
flag = [0x8a,0x07,0x72,0x76,0x8d,0x7d,0x4d,0x51,0x35,0xde,0x88,0x16,0xd4,0x04,0xf9,
0x0e,0x08,0xcf,0xcc,0x7c,0x0f,0x0d,0x09,0x5e,0xd5,0x7e,0xe4,0x4b,0xc4,0xf3,0x1c,0xaf,
0x12,0xe4,0xa0,0xae,0xf6,0x69,0xc9,0xd2,0xe0,0xa7,0x01,0x0e,0x1a,0x57,0x70,0x92,0x61,
0x49,0x7a,0x43,0x27,0x29,0x89,0xb5,0x92,0x2e,0x6a,0xa6,0xdb,0x2f,0xc6,0xa9,0x6e,0x8f,
0x34,0x90,0x59,0xfc,0x2d,0x91,0x66,0xeb,0xbe,0x0d,0xf4,0x05,0x0b,0x1b,0xcb,0x18,0x74,
0xf9,0x82,0x81,0xbc,0x04,0xd9,0x75,0x8e,0x2d,0x97,0x07,0x7c,0x7d,0x18,0xc8,0x3d,0x4f,0xc0,0xa5,0x6a,0xd7]flag_1 = []# key异或
for i in range(len(flag)):flag_1.append((flag[i] ^ key[i%len(key)]))
print(flag_1)
print()
key_1 = [1,1,0,0,-1,-1,-2,-2]
for i in range(len(flag)):print(chr((flag_1[i] ^ 0x33) + key_1[i%8]),end="")# flag{6e2480b3-4f02-4cf1-9bc0-123b75f9a922}
例题2:
题目: [羊城杯 2024]sedRust_happyVm | NSSCTF
- 根据输出的字符串快速定位到关键函数:
- 先给flag在内存打上硬件断点:
F9块定位到访问flag的位置,开始会停在这里:
分析汇编,多次尝试输入flag,以及根据下面对flag的检查,可以初步判断下面这部分程序的作用值检查flag是否合法,flag的头是否为 "DSACTF" 还有flag的长度是否为0x28:
输入 DASCTF{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} 即可绕过这部分检查,继续给flag多上几个断点:
继续F9 运行断在这里:
分析汇编、结合内存,可以看到这里将flag的{}中的内容取出 换到了另外一个内存空间,原来的flag空间被释放掉,给新的内粗上断点:
F9后程序停在这里,:
分析汇编、观察内存后不难发现这是一个base64编码(没有编码表),下面这段程序就是做类似的base64编码,3个字符一组 8 * 3 = 6 * 4 :
在另外一个内存空间存放base64编码的结果,仍然在这里下断点:
程序后续停在这里:
- 看这里的整体框架不难发现应该是又对base64编码后的flag(base_flag)开始了加密处理 (下面每一个小框框都是类似的处理流程),后续对vm虚拟机位置的部分开始分析:
根据断点位置,观察他是如何拿出base_flag的数据,放在了哪里。分析汇编观察寄存器的变化,不难发现他将base_flag两个一组取出,随后移位、相加、与,最后将取出的base_flag数据 与 程序本身的常数 0x0B1000018结合在一起,传入了vmp函数 进行加密:
仔细观察汇编、以及寄存器,不难发现vmp函数是没有任何返回值,那最后要如何判定flag是正确与否呢。
- 这里先快速定位到输出flag 正确的位置:
可以看到上面只有唯一一个位置能跳转到这里,暂时找过去观察。可以看到这里在最后一次加密后将一个内存区域与 0 做比较,如果为0则跳转到上面位置 输出You Get FLAG! :
所以在vmp函数中,应该是存在比较工作,在比较后会根据flag的正确与否来设置 内存区域[rsp+0C88h+check]的值,
而且在所以vmp函数处理完成后,只有这一个位置对改内存区域进行了比较。所以前面任意一次vmp函数,对base_flag数据处理的结果都会影响改内存区域(他是唯一判断flag正确的条件)。
- 先看一眼vmp函数,根本一眼看不到头,狗都不看:
这里根据上面的内存区域来反推,定位到在vmp函数中 flag正确与否的判断位置:
先给内存下一个硬件断点:
F9快速定位到修改该内存的空间:
可以发现在这里唯一修改了 该内存空间,修改的 条件是a1[1048]为1 :
在看一下哪里影响了 a1[1048] 的值,上面对a1的交叉引用可以看到只有这两个位置修改了a1[1048],一个加法操作,一个异或操作:
所以这两个位置是判断 flag释放正确的关键,该处下断点 (别的位置是否有修改这该处内存区域的值,可以用硬件断点如何完全调试一遍vmp函数即可):
- 从新回去找进入vmp函数时 传入的base_flag数据,毕竟vmp函数可能要对base_flag进行加密:
在进入vmp前,将base_flag 和 程序自带的立即数0xB1000018 一起放在了rdx寄存器中:
步入vmp函数,观察第一次rdx寄存器被访问的位置(有可能base_flag数据会被转移、或者加密):
这里可以看到将edx的数据置入了一片内存区域中:
给该处打上硬件断点(注意第二、三个值才是base_flag中取出的,第一个0x18是程序的立即数),后续edx寄存器的值被修改,就只有该内存区域存在base_flag数据:
F9后断在这里(这里会在上面加法操作的位置停下,直接步过不用管,因为没对flag进行加密),将base_flag数据取出 给到 eax 和 ecx,然后置入内存空间:
上面下断点,F9,这里将另外一个base_flag数据取出,置入内存中:
继续F9,断在这里,虽然改掉了base_flag但这里并不是加密,或者判断flag是否正确:
继续F9,断在这里:
再F9,会断再之前那个加法位置,观察此时的寄存器和内存,都没有base_flag的参数,所以直接步过
继续F9,直到触发硬件断点(访问到了base_flag数据)。在这里访问到了这前置入内存的base_flag数据,并转移到了另外一个内存空间中,并将原来的数据清空:
给转移的base_flag数据在内存上下断点,继续F9,再次断在加法操作位置,这里内存和寄存器上的值都不是base_flag数据,所以直接跳过
继续F9,这里将转移的base_flag数据取出,转移到另外一片内存中,继续下断点:
F9,断在异或操作的位置,观察对应内存和寄存器上的值,此时寄存器eax在再次转移的内存上取出了base_flag数据,并与另外一个内存上的数据进行异或,所以这力可能是对base_flag的一次加密、或者比较:
此时的异或值为0,而base_flag数据为0x18,明显不想等,异或出来的结果肯定不为0,所以如果这个是比较操作的话,后续肯定会根据异或的结果(非0),来修改最终判定条件,观察异或完后的操作是否对最终判定条件 进行了修改,单步发现在异或结束后,直接退出了该函数,返回到了vmp,所以上面的异或操作是对flag的一次加密 ,加密结果放在了内存中。打上断点:
F9,再次断在了异或操作上,继续用上次的方法来判定该次异或是否为比较操作,这次异或 ==> 取出了原先放入的base_flag数据,并与上次异或后的值再次异或:
该次异或完成后断在了要修改判定条件的位置 ,说明上次异或操作时一个比较 ==> 第一次异或后加密的值 与 内存上的值比较,两者相等才符合条件:
这里可以提取出第一次异或时内存上的数据,和第二次异或时al寄存器上的数据,两则异或来还原出第一个base_flag。
两外,这位两个位置的断点,有时候ida会设置为Unresolved 也就是未解析的状态,这里的原因不清楚,即使在异或函数中从新打上断点,只有再运行一个汇编代码,该断点就又会变成Unresolved。这就只能再程序的断点处观察内存和寄存器的值了:
第二个base_flag数据处理,继续F9:
F9后再次断在异或位置,这里寄存器al上是base_flag数据,内存[rsi+418h]上是与之异或的值,异或加密完成后退出该异或函数:
F9,再次停在异或位置,这次是内存上是上次异或的值 al寄存器上是与之比较的值 ,:
异或完成后,判定结果是否为0,来修改最总的判定条件:
- 综上vmp对base_flag数据的处理 ==> 一次传入两个base_flag数据,分别安排值与之异或加密 、然后异或一个正确的值根据结果是否为0 来修改最终的判定条件,进而完成比较操作,两个异或的数组都能从内存、或者寄存器上提取出来。经过多次vmp函数将所以base_flag数据处理完成,最后查看最终的判定条件 == 0。
要验证异或的值与flag是否有关,可以每次输入不同的flag,来比较每次的异或值是否相同。
- 最后提取出来的这两组异或值,相互异或还原base_flag,再对base_flag解码,还原出输入的flag:
xor_key = [0,0x82,0x11,0x92,0xa8,0x39,0x82,0x28,0x9a,0x61,0x58,0x8B,0xa2,0x43,0x68,0x89,0x04,0x8F,0xB0,0x43,0x49,0x3A,0x18,0x39,0x72,0x0C,0xBA,0x76,0x98,0x13,0x8B,0x46,0x33,0x2B,0x25,0xA2,0x8B,0x27,0xB7,0x61,0x7C,0x3F,0x58,0x56]
res = [0x18,0xb1,0x09,0xA4,0xa6,0x2a,0x9e,0x1B,0x96,0x57,0x5d,0xAD,0xAE,0x75,0x65,0xAC,0x09,0x8C,0xA0,0x76,0x47,0x2C,0x10,0x01,0x7C,0x0F,0xBA,0x47,0x95,0x30,0x9B,0x74,0x3F,0x2D,0x2D,0x9A,0x87,0x31,0xBA,0x43,0x70,0x2C,0x4C,0x56]
base = []
for i in range(len(res)):base.append( xor_key[i] ^ res[i] )
print(base)# 类似base解码 6bit ==> 8bit
tmp = ""
for i in range(len(base)):tmp += "{:0>6}".format(bin(base[i])[2:])
print(len(tmp))for i in range(0,len(tmp),8):print(chr(int(tmp[i:i+8],2)),end="")
# DASCTF{c669733af3ce4459b88016420b81cb15}
这给一个ida脚本动调提取数据的脚本:
主要函数解释:
start_process(path, args, sdir) :启动进程并附加调试器,可以指定调试的参数
run_to(ea) :控制调试器,运行到指定地址ea处
wait_for_next_event(WFNE_SUSP|WFNE_CONT, -1) : 等待直到进程挂起(WFNE_SUSP) 然后继续执行(WFNE_CONT),这里前提是要在提取数据的位置 打断点,触发断点时进程挂起,提取完数据后继续执行
get_wide_byte(ea)、get_wide_word(ea)、get_wide_dword(ea):获取指定地址ea处的值(1字节,2字节,4字节)
get_reg_value("ECX")、get_reg_value("CL") :获取指定寄存器的值
auto res = object() :声明一个数组对象,大小在使用的时候自动变化
最好配合断点,在该位置提取数据(必须要先打断点),且一个断点对应一个wait_for_next_event(WFNE_SUSP|WFNE_CONT, -1) :
#include <idc.idc>static main() {auto max_eax, max_ebx, second_ebx, third_eax;auto eax, ebx, ecx, ebp, addr_val;auto res = object(); // 一个数组对象auto path = "C:\\Users\\BKBQWQ\\Desktop\\rust1.exe"; // 路径auto args = "arg1 arg2"; // 命令行参数auto sdir = "C:\\Users\\BKBQWQ\\Desktop"; // 初始目录// 启动调试器if (start_process("","","") != 1) // start_process(path, args, sdir) ==> 使用默认配置{message("Failed to start the process\n");return;}// 循环提取数据auto code;auto i;for (i = 0; i < 31; i++) {// run_to(0x0007FF72FA159B4); // 运行到指定位置 后获取数据code = wait_for_next_event(WFNE_SUSP|WFNE_CONT, -1); // 等待一个暂停事件进程挂起 然后继续执行 直到下一个挂起点(前提是要打断点)// 获取指定地址处的数据ebp = get_reg_value("EBP");addr_val = get_wide_byte(ebp); // 获取指定地址处的数据 ==> 1个字节addr_val = get_wide_word(ebp); // 获取指定地址处的数据 ==> 2个字节addr_val = get_wide_dword(ebp); // 获取指定地址处的数据 ==> 4个字节// 获取寄存器的数据tmp1 = get_reg_value("ECX"); // 直接获取 CL 寄存器的值tmp2 = get_reg_value("CL"); // 直接获取 CL 寄存器的值tmp3 = get_reg_value("eax"); // 直接获取 eax 寄存器的值set_reg_value(tmp2,"rdx"); // 设置rdx寄存器的值// msg("%d,", ecx); // 输出结果res[i] = ecx; // 用数组存储提取出来的结果}msg("\n数据个数:%d \n数据值:",i);// 遍历对象 x 的属性并输出auto j;for (j = 0; j < i; j++) {msg("%d,", res[j]);}msg("\nout ...");
}
相关文章:

网络安全逆向分析之rust逆向技巧
rust逆向技巧 rust逆向三板斧: 快速定位关键函数 (真正的main函数):观察输出、输入,字符串搜索,断点等方法。定位关键 加密区 :根据输入的flag,打硬件断点,快速捕获程序中对flag访问的位置&am…...
Docker容器化技术概述与实践
哈喽,大家好,我是左手python! Docker 容器化的基本概念 Docker 容器化是一种轻量级的虚拟化技术,通过将应用程序及其依赖项打包到一个可移植的容器中,使其在任何兼容 Docker 的环境中都能运行。与传统的虚拟机技术不同…...
win中将pdf转为图片
0 资料 博客 1 正文 直接使用这个软件即可https://sourceforge.net/projects/pkpdfconverter/...

Leetcode 2494. 合并在同一个大厅重叠的活动
1.题目基本信息 1.1.题目描述 表: HallEvents ----------------- | Column Name | Type | ----------------- | hall_id | int | | start_day | date | | end_day | date | ----------------- 该表可能包含重复字段。 该表的每一行表示活动的开始日期和结束日期&…...

vue+elementui 网站首页顶部菜单上下布局
菜单集合后台接口动态获取,保存到store vuex状态管理器 <template><div id"app"><el-menu:default-active"activeIndex2"class"el-menu-demo"mode"horizontal"select"handleSelect"background-…...

网络安全-等级保护(等保) 3-3-1 GB/T 36627-2018 附录A (资料性附录) 测评后活动、附 录 B (资料性附录)渗透测试的有关概念说明
################################################################################ GB/T 36627-2018 《信息安全技术 网络安全等级保护测试评估技术指南》对网络安全等级保护测评中的相关测评技术进行明确的分类和定义,系统地归纳并阐述测评的技术方法,概述技术性安全测试和…...

pytorch3d+pytorch1.10+MinkowskiEngine安装
1、配置pytorch1.10cuda11.0 pip install torch1.10.1cu111 torchvision0.11.2cu111 torchaudio0.10.1 -f https://download.pytorch.org/whl/cu111/torch_stable.html 2、配置 MinkowskiEngine库 不按下面步骤,出现错误 1、下载MinkowskiEngine0.5.4到本地 2、查看…...

AI Infra运维实践:DeepSeek部署运维中的软硬结合
发布会资料 《AI Infra运维实践:DeepSeek部署运维中的软硬结合》 袋鼠云运维服务 1、行业痛点 随着数字化转型的深入,企业面临的运维挑战日益复杂,所依托的平台在长期使用的过程中积累了各式各样的问题或者难点。这些问题不仅影响效率&…...

MySQL体系架构解析(二):MySQL目录与启动配置全解析
MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录,这个目录下存放着许多可执行文件。与其他系统的可执行文件类似,这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中,用…...
深度学习在RNA分子动力学中的特征提取与应用指南
深度学习在RNA分子动力学中的特征提取与应用指南 引言:RNA结构动力学与AI的融合 RNA作为生命活动的核心分子,其动态构象变化直接影响基因调控、蛋白合成等关键生物过程。分子动力学(Molecular Dynamics, MD)模拟通过求解牛顿运动方程,可获取RNA原子级运动轨迹(时间尺度…...

K8s基础一
Kubernetes 架构 Kubernetes 背后的架构概念。 Kubernetes 集群由一个控制平面和一组用于运行容器化应用的工作机器组成, 这些工作机器称作节点(Node)。每个集群至少需要一个工作节点来运行 Pod。 工作节点托管着组成应用负载的 Pod。控制平…...

2025五大免费变声器推荐!
在游戏开黑时想靠声音搞怪活跃气氛,或是在直播中用独特声线吸引观众,又或者给视频配音时想尝试不同角色 —— 但市面上的变声软件要么收费高昂,要么效果生硬、操作复杂,难道找到一款好用又免费的变声器真的这么难? 今…...
StringRedisTemplete使用
StringRedisTemplate是Spring Data Redis提供的一个模板类,用于简化对Redis的操作。它特别适合处理字符串类型的数据,并且封装了一系列常用的Redis命令,使开发者能够以更简洁的方式进行Redis操作。本文将详细介绍 StringRedisTemplate的使用方…...

SDC命令详解:使用set_min_capacitance命令进行约束
相关阅读 SDC命令详解https://blog.csdn.net/weixin_45791458/category_12931432.html?spm1001.2014.3001.5482 目录 指定最小需驱动电容值 指定对象列表/集合 简单使用 写在最后 set_min_capacitance命令用于设置输入端口的最小需驱动电容(设置了输入端口的min_c…...

几何引擎对比:OpenCasCade、ACIS、Parasolid和CGM
概述 从技术架构与行业实践来看,OpenCasCade 凭借开源生态与轻量化设计形成差异化竞争力,尤其适合预算敏感、需定制开发或依赖开源工具链的场景;而 ACIS、Parasolid 等商业内核则通过工业级精度优化与主流 CAD 深度绑定占据大型企业市场&…...
OD 算法题 B卷【猴子吃桃】
文章目录 猴子吃桃 猴子吃桃 猴子喜欢吃桃,桃园有N棵桃树,第i棵桃树上有Ni个桃,看守将在H(>N)小时后回来;猴子可以决定吃桃的速度K(个/小时),每个小时他会选择一棵桃树,从中吃掉K个桃,如果这…...

汽车安全体系:FuSa、SOTIF、Cybersecurity 从理论到实战
汽车安全:功能安全(FuSa)、预期功能安全(SOTIF)与网络安全(Cybersecurity) 从理论到实战的安全体系 引言:自动驾驶浪潮下的安全挑战 随着自动驾驶技术从L2向L4快速演进,汽车安全正从“机械可靠…...

Excel-vlookup -多条件匹配,返回指定列处的值
前提:先了解vlookup 的简单使用, 参照:https://blog.csdn.net/yanweijie0317/article/details/144886106?spm1011.2124.3001.6209 要求:按照Sheet0的B列和I列,在Sheet1中查找H列。 函数: VLOOKUP(B509&a…...

Python异步爬虫与代理完美结合
为了编写一个高性能的异步爬虫,并使用代理IP,我们可以使用以下技术栈:aiohttp (用于异步HTTP请求)、asyncio (用于异步编程)、代理IP可以使用一个代理池,我们从文件中读取或者从API获…...
惠普HP Deskjet 9600 打印机信息
基本参数 产品定位:彩色喷墨打印机。打印速度:14 页 / 分钟。最高分辨率:48001200dpi。打印内存:8MB4。打印语言:HP PCL 3 增强型。打印负荷:每月 5000 页。接口类型:USB、并口。 功能特点 自动…...
Hive的Parquet格式优化方法
一、Parquet格式的特点与优势 1. 列式存储架构 核心特点:数据按列存储,同一列的数据连续存储在文件中,而非行式存储的“整行连续存储”。优势: 查询性能高:仅读取查询所需列的数据,减少I/O量(如SELECT name FROM table仅扫描name列)。压缩效率高:同一列数据类型一致,…...
ADI硬件笔试面试题型解析下
本专栏预计更新60期左右。当前第17期-ADI硬件. ADI其硬件工程师岗位的招聘流程通常包括笔试和多轮技术面试,考察领域涵盖模拟电路设计、数字电路、半导体器件和信号处理等。 本文通过分析平台上的信息,汇总了ADI硬件工程师的典型笔试和面试题型,并提供详细解析和备考建议,…...
服务器租用:高防CDN和加速CDN的区别
CDN全称为内容分发网络,其主要的作用原理能够加快网站的数据传输的速度,随着技术的快速发展,CDN也分为高防CDN和加速CDN两种不同的类型,本文将为大家介绍一下高防CDN和加速CDN两者之间的区别有哪些? 高防CDN能够有效抵…...

吃透 Golang 基础:数据结构之 Map
文章目录 Map概述初始化删除访问不存在的 key 返回 value 的零值遍历 mapmap 自身的零值map 索引时返回的第二个参数使用 map 实现 set Map Hash Map 是无序的 key/value 对集合,其中所有的 key 都是不同的。通过给定的 key 可以在常数时间复杂度内完成检索、更新或…...
ABP VNext 与 Neo4j:构建基于图数据库的高效关系查询
ABP VNext 与 Neo4j:构建基于图数据库的高效关系查询 🚀 在社交网络、权限图谱、推荐系统等应用场景中,关系链深度和复杂度远超传统关系型数据库的表达能力。本文基于 ABP VNext 框架,集成 Neo4j 图数据库,构建一套高…...
数论——同余问题全家桶3 __int128和同余方程组
数论——同余问题全家桶3 __int128和同余方程组 快速读写和__int128快速读写__int128 中国剩余定理和线性同余方程组中国剩余定理(CRT)中国剩余定理OJ示例模板题曹冲养猪 - 洛谷模板题猜数字 - 洛谷 扩展中国剩余定理扩展中国剩余定理OJ示例模板题扩展中国剩余定理(…...
leetcode47.全排列II:HashSet层去重与used数组枝去重的双重保障
一、题目深度解析与重复排列问题 题目描述 给定一个可能包含重复数字的数组nums,返回其所有不重复的全排列。解集不能包含重复的排列,且排列可以按任意顺序返回。例如: 输入:nums [1,1,2]输出:[[1,1,2],[1,2,1],[2…...

5.Nginx+Tomcat负载均衡群集
Tomcat服务器应用场景:tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选。一般来说,Tomcat虽然和Apache或…...

React项目的状态管理:Redux Toolkit
目录 1、搭建环境 2、Redux Toolkit 包含了什么 3、使用示例 (1)创建user切片 (2)合并切片得到store (3)配置store和使用store 使用js来编写代码,方便理解一些 1、搭建环境 首先…...

跨界破局者鲁力:用思辨与创新重塑汽车流通行业标杆
来源:投资家 在汽车流通行业深度变革的浪潮中,东莞东风南方汽车销售服务有限公司塘厦分公司总经理鲁力历经近二十年行业深耕,构建了一条从汽车销售顾问到区域运营掌舵者的进阶范本。作为东风日产体系内兼具理论建构与实战穿透力的标杆管理者…...