【学习笔记】《逆向工程核心原理》02.小段标记法、IA-32寄存器、栈、abex‘crackme、栈帧
文章目录
- 1. 字节序
- 1.1. 大端序与小端序
- 1.2. 在OllyDbg中查看小端序
- 2.IA-32寄存器
- 2.1. 什么是CPU寄存器
- 2.2. IA-32寄存器
- 2.2.1. 通用寄存器
- 2.2.2. 段寄存器
- 2.2.3. 程序状态与控制寄存器
- 2.2.4. 指令指针寄存器
- 3. 栈
- 1.1. 栈的特征
- 3.1.2. 栈操作实例
- 4. abex'crackme
- 4.1. 开始调试
- 4.1.1. 破解
- 4.1.2. 将参数压入栈
- 5. 栈帧
- 5.1. 调试示例:stackframe.exe
- 5.1.1. 开始执行main()函数&生成栈帧
- 5.1.2. 设置局部变量
- 5.1.3. add函数参数传递与调用
- 5.1.4. 开始执行add函数&生成栈帧
- 5.1.5. 设置add函数的局部变量(x,y)
- 5.1.6. add运算
- 5.1.7. 删除函数add的栈帧&函数执行完毕(返回)
- 5.1.8. 从栈中删除函数add的参数(整理栈)
- 5.1.9. 调用printf函数
- 5.1.10. 设置返回值
- 5.1.11. 删除栈中&main函数终止
- 6. 设置OllyDbg选项
- 6.1. 反汇编选项
- 6.2. 分析1选项
思维导图

1. 字节序
- 字节序分为大端序与小端序
- 字符串最后是以NULL结尾的
1.1. 大端序与小端序
大端序:内存地址低位存储数据的高位、内存地址高位存储数据的低位
小端序:内存地址高位存储数据的高位、内存地址低位存储数据的低位
采用大端序保存多字节数据非常直观,它常用于大型UNIX服务器的RISC系列的CPU中。此外,网络协议中也经常采用大端序方式。了解这些,对从事x86系列应用程序的开发人员以及代码逆向分析人员具有非常重要的意义,因为通过网络传输应用程序使用数据时,往往都需要修改字节序。
1.2. 在OllyDbg中查看小端序
代码
#include "windows.h"BYTE b = 0x12;
WORD w = 0x1234;
DWORD dw = 0x12345678;
char str[] = "abcde";int main(int argc, char *argv[])
{BYTE lb = b;WORD lw = w;DWORD ldw = dw;char *lstr = str;return 0;
}
直接goto到401000 main()
函数处
全局变量b、W、dw、str的地址分别为413880、413888、413884、41388c。下面通过OllyDbg的数据窗口来分别查看它们所在的内存区域
可以发现变量w的数据采用小段存储
2.IA-32寄存器
2.1. 什么是CPU寄存器
寄存器(Register)是CPU内部用来存放数据的一些小型存储区域,它与我们常说的RAM(RandomAccessMemory,随机存储器、内存)略有不同。CPU访问(Access)RAM中的数据时要经过较长的物理路径,所以花费的时间要长一些;而寄存器集成在CPU内部,拥有非常高的读写速度。
2.2. IA-32寄存器
IA-32是英特尔推出的32位元架构,属于复杂的指令集架构,它提供了非常丰富的功能,且支持多种寄存器。
通用寄存器(General PurposeRegisters,32位,8个)
段寄存器(Segment Registers,16位,6个)
程序状态与控制寄存器(ProgramStatus and Control Registers,32位,1个)
指令指针寄存器(InstructionPointer,32位,1个)
2.2.1. 通用寄存器
为了实现对低16位的兼容,各寄存器又可以分为高(H:High)低(L:Low)
几个独立寄存器。下面以EAX为例讲解。
EAX:(0~31)32位
AX:(0~15)EAX的低16位
AH:(8~15)AX的高8位
AL:(0~7)AX的低8位
若想全部使用4个字节(32位),则使用EAX;若只想使用2个字节(16位),只
要使用EAX的低16位部分AX就可以了。
AX又分为高8位的AH与低8位的AL两个独立寄存器。借助这种方式,可以根据不同情况把一个32位的寄存器分别用作8位、16位、32位寄存器。后面的程序调试中,我们分析汇编代码就能很容易地理解它们。
EAX:(针对操作数和结果数据的)累加器
EBX:(DS段中的数据指针)基址寄存器
ECX:(字符串和循环操作的)计数器
EDX:(IO指针)数据寄存器
EBP:(SS段中栈内数据指针)扩展基址指针寄存器
ESI:(字符串操作源指针)源变址寄存器
EDI:(字符串操作目标指针)目的变址寄存器
ESP:(SS段中栈指针)栈指针寄存器
此外:EAX一般用在函数返回值中。所有的win32API 函数都会先把返回值保存到EAX再返回
2.2.2. 段寄存器
IA-32的保护模式中,段是一种内存保护技术,它把内存划分为多个区段,并为每个区段赋、范围、访问权限等,以保护内存。
此外,它还同分页技术(Paging)一起用于将虚拟内存变更为实际物理内存。段内存记录在SDT(SegmentDescriptorTable,段描述符表)中,而段寄存器就持有这些SDT的索引(index)。
CS:Code Segment,代码段寄存器
SS:Stack Segment,栈段寄存器
DS:Data Segment,数据段寄存器
ES:Extra(Data)Segment,附加(数据)段寄存器
FS:DataSegment,数据段寄存器
GS:DataSegment,数据段寄存器
2.2.3. 程序状态与控制寄存器
EFLAGS:FlagRegister,标志寄存器
大小为4字节(32位)由原来的16位FLAGS寄存器拓展而来
学习代码逆向分析技术的初级阶段,只要掌握3个与程序调试相关的标志即可,
分别为ZF(ZeroFlag,零标志)、OF(OverflowFlag,溢出标志)、CF(CarryFlag,进位标志)。
2.2.4. 指令指针寄存器
●EIP:InstructionPointer,指令指针寄存器
指令指针寄存器保存着CPU要执行的指令地址,其大小为32位(4个字节),由原16位IP寄存器扩展而来。程序运行时,CPU会读取EIP中一条指令的地址,传送指令到指令缓冲区后,EIP寄存器的值自动增加,增加的大小即是读取指令的字节大小。
这样,CPU每次执行完一条指令,就会通过EIP寄存器读取并执行下一条指令。
与通用寄存器不同,我们不能直接修改EIP的值,只能通过其他指令间接修改,这些特定指令包括JMP、Jcc、CALL、RET。此外,我们还可以通过中断或异常来修改EIP的值。
3. 栈
栈内存在进程中的作用如下:
(1)暂时保存函数内的局部变量。
(2)调用函数时传递参数。
(3)保存函数返回后的地址。
栈其实是一种数据结构,它按照FILO(FirstInLastOut,后进先出)的原则存储数据。
1.1. 栈的特征
一个进程中,栈顶指针(ESP)初始状态指向栈底端。执行PUSH命令将数据压人栈时,栈顶指针就会上移到栈顶端。执行POP命令从栈中弹出数据时,若栈为空,则栈顶指针重新移动到栈底端。
换言之,栈是一种由高地址向低地址扩展的数据结构,图中,栈是由下往上扩展的。
由于栈具有这种特征,所以我们常常说“栈是逆向扩展的”,向栈中压数据就像一层层砌砖,每向上砌一层,砖墙就增高一点儿。
3.1.2. 栈操作实例
调试器加载附件 Stack.exe
可以发现栈顶指针的值为 19FF74 ,下面也可以看到ESP指向的地址及其值
然后我们执行 PUSH 100
观察ESP值的变化
发现ESP变成了 19FF70 少了4个字节。并且当前栈顶指针指向 19FF70地址,该地址中保存着100这个值。
就是说 执行 PUSH 100
命令时, 数值100被压入栈 ESP随之向上移动。即ESP值减少了4个字节。
然后我们执行 POP EAX
命令
执行后,ESP的值又增加了4个字节,变回了 19FF74 ,栈又变成了原来的初始状态。 并且将原来存储在栈中的数值100 保存到了EAX寄存器中
向栈压入数据时,栈顶指针减小,向低地址移动;从栈中弹出数据时,栈顶指针增加,向高地址移动。
请记住:栈顶指针在初始状态下指向栈底。这就是栈的特征
4. abex’crackme
运行这个 abex'crackme
这个程序,会提示两个信息
4.1. 开始调试
虽然看不到在搞什么名堂,还是直接用OD进行调试吧
进来后会发现EP代码非常短。这是因为这个程序是用汇编语言编写出来的可执行文件
使用VC++、VC、Delphi等开发工具编写程序时,除了自己编写的代码外,还有一部分启动函数是由编译器添加的,经过反编译后,代码看上去就变得非常复杂。
但是如果直接使用汇编语言编写程序,汇编代码会直接变为反汇编代码。观察图6-3中的代码可以看到,main
直接出现在EP中,简洁又直观,充分证明了这是一个直接用汇编语言编写的程序。
分析代码可以发现 在第一个弹框点击确认后,程序会调用 GetDriveType()
API,获取C驱动器的类型。 (大部分都是HDD类型),然后操作它使之被识别为CD-ROM类型。然后就会输出 成功后的提示
4.1.1. 破解
我们使用f8去一步一步执行,可以发现在 JE short 0040103D
处因为条件不满足导致无法跳转到 40103D
从而进入了错误的判断当中
这里我们对 je short 40103d
反汇编 把 je
改成 jmp即可
然后运行即可进入正确的代码逻辑中
4.1.2. 将参数压入栈
这里介绍一下函数调用时将函数参数压入栈中的方法
我们查看 40100-40100E
之间的命令
可以发现调用 messageboxwA
函数之前使用了4个PUSH命令,把函数需要的参数 逆序压入栈
然后这是C语言的函数调用代码
MessageBox(NULL, "Make me think your HD is a CD-Rom.", "abex' 1stCrackme", MB_OK|MB_APPLMODAL);
可以发现两者传入参数的顺序是不同的。
函数调用时的参数顺序(正序)与参数入栈时的顺序(逆序)相反。
这里就是因为栈的结构是FILO 先进后出,即出入栈会交换顺序
我们是要先把参数入栈,然后再出栈传递给函数进行调用。所以需要逆序入栈,从而使得是正序出栈
我们把程序执行到EIP= 40100E
处观察栈窗口
从这个栈中取出数据就是正序的了。也就可以正确的传递给函数参数进行调用
个人理解:因为栈是向低地址延申的。所以低地址是栈顶,高地址是栈底。所以出来的顺序就是
NULL
Make me ....
也就是正序的了。
5. 栈帧
作用: 栈帧在程序中用于声明局部变量、调用函数。
栈帧就是利用EBP寄存器访问栈内局部变量、参数、函数返回地址等的手段
与ESP寄存器不同:ESP承担栈顶指针的作用。而EBP寄存器则负责行驶栈帧指针的职能
程序运行中,ESP寄存器的值随时变化,访问栈中函数的局部变量、参数时,若以ESP值为基准编写程序会十分困难,并且也很难使CPU引用到准确的地址。
所以,调用某函数时,先要把用作基准点(函数起始地址)的ESP值保存到EBP,并维持在函数内部。
这样,无论ESP的值如何变化,以EBP的值为基准(base)能够安全访问到相关函数的局部变量、参数、返回地址,这就是EBP寄存器作为栈帧指针的作用。
●最新的编译器中都带有一个“优化”(Optimization)选项,使用该选项编译简单的函数将不会生成栈帧。
●在栈中保存函数返回地址是系统安全隐患之一,攻击者使用缓冲区溢出技术能够把保存在栈内存的返回地址更改为其他地址。
5.1. 调试示例:stackframe.exe
源代码
#include "stdio.h"long add(long a, long b)
{long x = a, y = b;return (x + y);
}int main(int argc, char* argv[])
{long a = 1, b = 2;printf("%d\n", add(a, b));return 0;
}
调试器加载程序 并goto到 401000处
5.1.1. 开始执行main()函数&生成栈帧
int main(int argc, char* argv[]){}
函数 main
是程序开始执行的地方,在 main
函数的起始地址(401020)处,按F2键设置个断点,然后按F9运行程序,程序运行到 main
函数的断点处暂停。
然后观察栈的变化
当前ESP的值为 19ff2c
,EBP的值为 19ff70
。切记地址 401250
保存在ESP(19ff2c)中,它是 main
函数执行完毕后要返回的地址。
观察代码可以发现 main
函数 一开始运行就会生成与其对应函数的栈帧
这里 PUSH EBP
就是把EBP的值压入栈。 main
函数中 EBP为栈帧指针,用来把EBP之前的值备份到栈中。(main
函数执行完毕,返回之前,该值会再次恢复)
下一条命令 MOV EBP,ESP
就是把ESP的值 传递给EBP。换言之,从这条命令开始,EBP就有和ESP相同的值,直到 main
函数执行完毕。EBP的值始终不变。 也就是说,我们通过EBP就可以安全访问到存储在栈中的函数参数与局部变量了
执行完 PUSH EBP
与 MOV EBP,ESP
后,函数 main
的栈帧就生成了(设置好了EBP)
然后在栈窗口 选择 地址->相对EBP
然后调试到 mov ebp,esp
可以发现当前EBP值与ESP值相同。 EBP处的数值是 19FF70
他是 main
函数开始执行时EBP持有的初始值。
5.1.2. 设置局部变量
分析源代码中的变量声明与赋值语句
long a = 1, b = 2;
在 main
函数中,上述代码用于在栈中为局部变量 a b分配空间,并赋初始值
如何分配空间?
SUB ESP,0x8
这里就是把ESP减去8个字节(因为a b是两个长整形,每个占用4个字节)开辟空间,以便将它们保存在栈中。
当为这两个变量开辟好空间后,在 main
函数内部,无论ESP的值怎么变化。变量a b的栈空间都不会受影响。由于EBP的值在 main
函数内部是固定不变的。所以,我们可以通过以它为基准进行访问函数的局部变量了。
通过指令
mov dword ptr ss:[ebp-0x4],0x1
mov dword ptr ss:[ebp-0x8],0x2
来设置值。
在界面中可能会显示
那是因为反汇编工具会将 ebp
作为基址,并对局部变量进行标注,以提高可读性
其中 local.1
表示一个局部变量。这里就是 a
变量
DWORDPTRSS:[EBP-4]
语句中,SS是StackSegment的缩写,表示栈段。由于Windows中使用的是段内存模型(Segment MemoryModel),使用时需要指出相关内存属于哪一个区段。其实,32位的WindowsOS中,SS、DS、ES的值皆为0,所以采用这种方式附上区段并没有什么意义。因EBP与ESP是指向栈的寄存器,所以添加上了SS寄存器。请注意,“DWORDPTR”与“SS:”等字符串可以通过设置OllyDbg的相应选项来隐藏。
执行完这两天命令后,查看栈内的情况可以发现已经将变量的值存储到栈内了
5.1.3. add函数参数传递与调用
源代码中调用了add函数 并且打印了返回值
printf("%d\n", add(a, b));
观察这5行代码,它表示了调用add()函数的全过程。
401000
处的函数就是 add
函数,函数 add
接受 a
b
这两个长整型参数。所以调用 add
函数之前 需要把这两个参数压入栈中。
值得注意的是:这里入栈的顺序与
add
函数的参数顺序正好相反。 这就是参数的逆向存储
即先入栈b 再入栈a
然后进入add函数内部进行分析
在执行函数之前,CPU会先把函数的返回地址入栈,用作函数执行完毕后的返回地址。
观察代码可以发现函数 add
在 40103c
处被调用。他的下一条命令地址是 401041
这就是 add
函数的返回地址。
可以发现此时CPU也把函数返回地址压入栈中了
5.1.4. 开始执行add函数&生成栈帧
add
函数前两行
long add(long a, long b)
{
函数开始执行时,栈中会单独生成与其对应的栈帧
执行后就会把原来EBP的值备份到栈中,然后把ESP的值传递给EBP
5.1.5. 设置add函数的局部变量(x,y)
源代码
long x=a, y=b
这里声明了两个长整型变量 x y并用a b 赋值给他们
首先开辟空间
SUB EBP,0x8
然后赋值
、
执行后的栈内情况
5.1.6. add运算
源代码
return (x+y);
用于返回两个局部变量之和
执行后eax的值就是3
5.1.7. 删除函数add的栈帧&函数执行完毕(返回)
对应原代码
return (x+y);
}
执行完加法运算后,要返回函数 add
在此之前,需要先删除 add
函数的栈帧
mov esp,ebp
这里与开始生成栈帧的命令 mov ebp,esp
向对应
生成栈帧时: 把函数开始执行时的ESP值放入EBP
删除栈帧时:把放入EBP中的ESP值还给ESP
执行完上面的命令后,地址
401003
处的SUB ESP,0x8
就会失效,即函数add
的两个局部变量x,y不在有效
然后 pop ebp
恢复函数 ADD
开始执行时备份到栈中的EBP值。它与 401000
处的 PUSH EBP
命令对应。 EBP值恢复为 19FF28
它是 main
函数的EBP值,到此 add
函数的栈帧就被删除了
可以看到此时ESP的值为 19ff14
此地址的值是 401041
它是执行 call 401000
命令时CPU存储到栈中的返回地址
然后执行retn命令后。存储在栈中的返回地址即被返回, 此时调用栈也已经完全返回到被调用到 add
函数之前的状态
5.1.8. 从栈中删除函数add的参数(整理栈)
现在,函数执行流已经返回到 main
函数中
然后执行 ADD esp,0x8
即回收空间。不需要a b参数了
这里与前面开辟空间的 SUB esp,0x8
相对应
被调函数执行完毕后,函数的调用者(Caller) 负责清理存储在栈中的参数,这种方式称为cdecl方式;
反之,被调用者(Callee) 负责清理保存在栈中的参数,这种方式称为stdcall方式。
这些函数调用规则统称为调用约定(CallingConvention),这在程序开发与分析中是一个非常重要的概念
5.1.9. 调用printf函数
对应源代码
printf("%d\n",add(a,b));
由于上面的printf
函数有2个参数,大小为8个字节(32位寄存器+32位常量=64位=8字节),
所以在 40104F
地址处使用 ADD
命令,将ESP加上8个字节,把函数的参数从栈中删除。函数 printf
执行完毕并通过 ADD
命令删除参数后 栈内情况
5.1.10. 设置返回值
对应源代码
return 0;
main
函数使用该语句设置返回值0
汇编代码 xor eax,eax
异或清0 且比 MOV eax,0
更快
5.1.11. 删除栈中&main函数终止
对应源代码
return 0;
}
主函数终止,同 add
函数一样,需要先从栈中删除其对应的栈帧
对应汇编代码
MOV ESP,EBP
POP EBP
执行后,main
函数栈帧被删除。其局部变量,a b 也不再生效。
此时与 main
函数开始的栈内情形是一样的
然后执行 retn
程序流跳转到返回地址 401250
处,该地址指向Visual C++的启动函数区域。随后执行进程终止代码。
6. 设置OllyDbg选项
6.1. 反汇编选项
Alt+O
6.2. 分析1选项
关闭后就不会显示 Local.1
这种形式了
笔记仅记录自己学习。里面有大量书中原文。如有侵权,请联系我删除。
相关文章:
【学习笔记】《逆向工程核心原理》02.小段标记法、IA-32寄存器、栈、abex‘crackme、栈帧
文章目录 1. 字节序1.1. 大端序与小端序1.2. 在OllyDbg中查看小端序 2.IA-32寄存器2.1. 什么是CPU寄存器2.2. IA-32寄存器2.2.1. 通用寄存器2.2.2. 段寄存器2.2.3. 程序状态与控制寄存器2.2.4. 指令指针寄存器 3. 栈1.1. 栈的特征3.1.2. 栈操作实例 4. abexcrackme4.1. 开始调试…...
固定表头、首列 —— uniapp、vue 项目
项目实地:也可以在 【微信小程序】搜索体验:xny.handbook 另一个体验项目:官网 一、效果展示 二、代码展示 (1)html 部分 <view class"table"><view class"tr"><view class&quo…...
用友U9二次开发-问题记录
学习资料:链接: https://pan.baidu.com/s/13JbKSSRkSn2V6-dYX5zKFQ 提取码: p9at 页面 &__dmtrue 客开插件 &Admintrue 开发者使用查看代码 插件 UI插件配置项 1.关闭热插拔 2.在configuration节点下加配置,多个在Web…...
python---pickle库
pickle库 pickle 是 Python 标准库中的一个模块,它可以将 Python 对象(如列表、字典、类实例等)转换为字节流,这个过程称为“序列化”;反之,也可以将字节流转换回 Python 对象,这个过程称为“反…...
如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
我在业余时间开发了一款自己的独立产品:升讯威在线客服与营销系统。陆陆续续开发了几年,从一开始的偶有用户尝试,到如今线上环境和私有化部署均有了越来越多的稳定用户。 随时近来 AI 大模型的火热,越来越多的客户,问…...
论文阅读 GMM-JCSFE Model(EEG Microstate)
Motor Imagery Recognition Based on GMM-JCSFE Model 1.问题与困境 1.1 微状态 将连续的EEG信号分解为一系列短暂的、稳定的“微状态”,每个微状态代表了大脑在特定时间窗口内的特定功能。微状态模型的核心思想是,大脑的活动可以看作是由一系列离散的…...
[杂学笔记] TCP和UDP的区别,对http接口解释 , Cookie和Session的区别 ,http和https的区别 , 智能指针 ,断点续传
文章目录 1. TCP和UDP的区别2. 对http接口解释3. Cookie和Session的区别4. http和https的区别5. 智能指针6.断点续传 1. TCP和UDP的区别 tcp的特点: 面向连接,可靠性高,全双工,面向字节流udp特点:无连接,不…...
Etcd的安装与使用
1.Etcd介绍 Etcd 是一个 golang 编写的分布式、高可用的一致性键值存储系统,用于配置共享和服 务发现等。它使用 Raft 一致性算法来保持集群数据的一致性,且客户端通过长连接 watch 功能,能够及时收到数据变化通知。 以下 是关于 …...
ROS实践(四)机器人建图及导航
一、概念 机器人导航是指机器人在环境中自主地从一个地点移动到另一个地点的过程。这个过程涉及到多个关键技术,包括定位、路径规划、避障等。机器人导航通常包括以下几个重要部分。 1. 定位 定位是机器人确定自己在环境中的位置的过程。常用的定位方法包括…...
Excel 中如何实现数据透视表?
Excel 中如何实现数据透视表? 数据透视表(PivotTable)是 Excel 中强大的数据分析工具,能够快速汇总、分析和展示大量数据。本文将详细介绍如何在 Excel 中创建和使用数据透视表。 1. 数据透视表的基本概念 数据透视表是一种交互…...
SQLiteStudio:一款免费开源跨平台的SQLite管理工具
目录 1.简介 2.下载与安装 3.实现分析 4.总结 1.简介 SQLiteStudio 是一款专门用于管理 SQLite 数据库的图形化工具,由波兰开发者开发并维护。由于 SQLite 以其轻量级、零配置、嵌入式等特性被广泛应用于各种小型项目、移动应用和桌面应用中,而 SQLi…...
实现Django和Transformers 构建智能客服大模型(模拟订单系统)
一、环境安装准备 #git拉取 bert-base-chinese 文件#创建 虚拟运行环境python -m venv myicrplatenv#刷新source myicrplatenv/bin/activate#python Django 集成nacospip install nacos-sdk-python#安装 Djangopip3 install Django5.1#安装 pymysql settings.py 里面需要 # 强制…...
【沐渥科技】氮气柜日常如何维护?
氮气柜的维护是确保其长期稳定运行、延长使用寿命和保持环境控制精度的关键。以下是沐渥氮气柜的日常维护和定期保养指南: 一、日常维护 柜体清洁 定期用软布擦拭柜体表面和内部,避免灰尘堆积。避免使用腐蚀性清洁剂,防止损伤密封条或传感器。…...
数据安全之策:备份文件的重要性与自动化实践
在信息化高速发展的今天,数据已成为企业运营和个人生活中不可或缺的重要资源。无论是企业的财务报表、客户资料,还是个人的家庭照片、学习笔记,数据的丢失或损坏都可能带来无法挽回的损失。因此,备份文件的重要性日益凸显…...
windows下玩转vllm:vllm简介;Windows下不能直接装vllm;会报错ModuleNotFoundError: No module named ‘vllm._C‘
文章目录 -1. Windows下不能直接装vllm前言ollama vs vllmOllamavLLMvllm简介核心特点PagedAttention内存优化高效推理应用场景安装与使用-1. Windows下不能直接装vllm 我其实很久之前就意识到这个事儿,后来太久没搞就又忘了。 昨天忙活了半宿,得来的确实一个无法解决的报错…...
目录《Vue 3 + TypeScript + DeepSeek 全栈开发实战》
在快速迭代的软件开发世界里,技术的融合与创新始终是推动行业前行的不竭动力。今天,我们站在了前端技术与大数据搜索技术交汇的十字路口,手中的工具不再仅仅是编码的利器,更是解锁未来应用无限可能的钥匙。正是基于这样的时代背景…...
for...of的用法与介绍
一、定义 for...of 是 ES6(ECMAScript 2015)引入的一种用于 遍历可迭代对象(Iterable)的循环语句 二、语法 for (const item of iterable) {// 代码块 }参数: iterable:一个可迭代对象(如数组…...
快速使用PPASR V3版不能语音识别框架
前言 本文章主要介绍如何快速使用PPASR语音识别框架训练和推理,本文将致力于最简单的方式去介绍使用,如果使用更进阶功能,还需要从源码去看文档。仅需三行代码即可实现训练和推理。 源码地址:https://github.com/yeyupiaoling/P…...
Aliyun CTF 2025 web ezoj
文章目录 ezoj ezoj 进来一看是算法题,先做了试试看,gpt写了一个高效代码通过了 通过后没看见啥,根据页面底部提示去/source看到源代码,没啥思路,直接看wp吧,跟算法题没啥关系,关键是去看源码 def audit_checker(even…...
推理模型对SQL理解能力的评测:DeepSeek r1、GPT-4o、Kimi k1.5和Claude 3.7 Sonnet
引言 随着大型语言模型(LLMs)在技术领域的应用日益广泛,评估这些模型在特定技术任务上的能力变得越来越重要。本研究聚焦于四款领先的推理模型——DeepSeek r1、GPT-4o、Kimi k1.5和Claude 3.7 Sonnet在SQL理解与分析方面的能力,…...
【H2O2 | 软件开发】事件循环机制
目录 前言 开篇语 准备工作 正文 概念 流程 事件队列类型 示例 结束语 前言 开篇语 本系列为短篇,每次讲述少量知识点,无需一次性灌输太多的新知识点。该主题文章主要是围绕前端、全栈开发相关面试常见问题撰写的,希望对诸位有所帮…...
LVTTL(Low Voltage Transistor-Transistor Logic)电平详解
一、LVTTL电平的定义与核心特性 LVTTL(低压晶体管-晶体管逻辑)是传统TTL(5V)的低电压版本,工作电压通常为3.3V,旨在降低功耗并适配现代低电压集成电路,同时保持与TTL的逻辑兼容性。其核心特点如…...
Manus:成为AI Agent领域的标杆
一、引言 官网:Manus 随着人工智能技术的飞速发展,AI Agent(智能体)作为人工智能领域的重要分支,正逐渐从概念走向现实,并在各行各业展现出巨大的应用潜力。在众多AI Agent产品中,Manus以其独…...
批量测试IP和域名联通性
最近需要测试IP和域名的联通性,因数量很多,单个ping占用时间较长。考虑使用Python和Bat解决。考虑到依托的环境,Bat可以在Windows直接运行。所以直接Bat处理。 方法1 echo off for /f %%i in (E:\封禁IP\ipall.txt) do (ping %%i -n 1 &…...
网络安全之tcpdump工具
引言 wireshark是一款非常不错的抓包软件,在图形化界面占绝对统治地位;尽管其在字符界面下有些许选项可供使用,但终究不太方便,下面我再介绍一款NB的终端抓包工具 tcpdump 1、混杂模式 linux的网卡有混杂模式一说,当开…...
TMS320F28P550SJ9学习笔记8:I2C通信的结构体寄存器配置的了解
继续学习IIC通信的寄存器配置方式:尝试使用寄存器方式配置了解I2C a 没条件完整测试IIC功能,具体的修改与测试留在下文,这里只贴出全部代码,就不提供工程了 文章提供测试代码讲解、完整工程下载、测试效果图 目录 IIC通信引脚&a…...
TypeScript类:面向对象编程的基石
一、从现实世界到代码世界 想象你要建造一栋房子,首先需要一张设计蓝图——它定义了房屋的结构(几个房间)、功能(卧室/厨房)和特性(材料/颜色)。在TypeScript中,class就是这个设计蓝…...
C语言学习笔记-进阶(10)自定义类型:结构体
1. 结构体类型的声明 前面我们在学习操作符的时候,已经学习了结构体的知识,这里稍微复习一下。 1.1 结构体回顾 结构是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。 1.1.1 结构体的声明 struct tag {member-…...
Java 大视界 -- Java 大数据在智能家居能源管理与节能优化中的应用(120)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
upload-labs-master通关攻略(9~12)
Pass-9 建立1.php <?php phpinfo();?> 上传时抓包 修改代码 在1.php后面加点号空格点号 放行后得到 Pass-10 将1.php放入 上传时抓包 修改代码 将1.php改为1.pphphp 上传后得到 Pass-11 将1.php改为1.png 上传时抓包 修改代码 ../upload/2.php%00 放行后得到 Pass…...
python语言总结(持续更新)
本文主要是总结各函数,简单的函数不会给予示例,如果在平日遇到一些新类型将会添加 基础知识 输入与输出 print([要输出的内容])输出函数 input([提示内容]如果输入提示内容会在交互界面显示,用以提示用户)输入函数 注释 # 单行注释符&…...
UI自动化测试 —— web端元素获取元素等待实践!
前言 Web UI自动化测试是一种软件测试方法,通过模拟用户行为,自动执行Web界面的各种操作,并验证操作结果是否符合预期,从而提高测试效率和准确性。 目的: 确保Web应用程序的界面在不同环境(如不同浏览器、操作系统)下…...
【CXX】6.6 UniquePtr<T> — std::unique_ptr<T>
std::unique_ptr 的 Rust 绑定称为 UniquePtr。有关 Rust API 的文档,请参见链接。 限制: 目前仅支持 std::unique_ptr<T, std::default_delete>。未来可能会支持自定义删除器。 UniquePtr 不支持 T 为不透明的 Rust 类型。对于在语言边界传递不…...
【网络协议安全】任务10:三层交换机配置
CSDN 原创主页:不羁https://blog.csdn.net/2303_76492156?typeblog三层交换机是指在OSI(开放系统互连)模型中的第三层网络层提供路由功能的交换机。它不仅具备二层交换机的交换功能,还能实现路由功能,提供更为灵活的网…...
C语言每日一练——day_4
引言 针对初学者,每日练习几个题,快速上手C语言。第四天。(连续更新中) 采用在线OJ的形式 什么是在线OJ? 在线判题系统(英语:Online Judge,缩写OJ)是一种在编程竞赛中用…...
文件系统调用(上) ─── linux第17课
目录 linux 中man 2和man 3的区别 文件内容介绍 C语言文件接口 示例: 输出信息到显示器,你有哪些方法 总结: 系统文件I/O 文件类的系统调用接口介绍 示例 open 函数具体使用哪个,和具体应用场景相关, write read close lseek ,类比C文件相关接…...
在 Spring Boot 中实现基于 TraceId 的日志链路追踪
1 前言 1.1 什么是 TraceId? TraceId 是一个唯一的标识符,用于跟踪分布式系统中的请求。每个请求从客户端发起到服务端处理,再到可能的多个微服务调用,都会携带这个 TraceId,以便在整个请求链路中进行追踪和调试。 1.2 日志链路追踪的意义 日志链路追踪可以帮助开发者…...
STM32 HAL库 CAN过滤器配置
之前在STM32 f407 CAN收发 基于HAL库和Cubemx配置_stm32f407can收发程序-CSDN博客这篇博文里写了一下配置CAN收发的方法,当时由于并没有使用过滤器的现实需求,所以就也没仔细研究。现在工作中确实需要用到过滤器了,有些项目中控制器和发动机E…...
C++ 控制结构与函数全面解析
引言 在 C 编程中,控制结构和函数是构建程序逻辑的关键要素。控制结构能够决定程序的执行流程,而函数则可以将代码模块化,提高代码的复用性和可维护性。本文将深入介绍 C 中的控制结构和函数的相关知识。 一、控制结构 1. if - else 语句 …...
基于django+pytorch(Faster R-CNN)的钢材缺陷识别系统
一、训练数据来源以及数据标注 数据来源于阿里云天池实验室公开数据集中的铝型材缺陷检测数据集APDDD 数据标注通过labelme进行标注,图片所有标注以转化为矩形标注,存放成json格式。 二、模型训练方式及结果 缺陷识别模型基于Faster R-CNN ResNet5…...
C++多态
多态 多态分为:静态多态(函数重载,运算符重载)和动态多态(派生类、虚函数) 二者区别:静态多态是在地址编译时绑定,而动态多态是在地址运行时绑定 动态多态的特点: 1.有继承关系 2.子类重写父类虚函数(就是跟父类行为函数名称一样,但是是作为子类的行为) 动态多态的…...
【一句话经验】ubuntu vi/vim 模式自动设置为paste
从centos过来,发现ubutun有些地方不习惯,尤其是vi的粘贴,默认自动进去了代码模式,导致每次粘贴必须得set paste,否则会出现问题。 解决办法非常简单,按照下面命令执行即可: cd ~ echo "…...
MongoDB 触发器实现教程
在传统的关系型数据库(如 MySQL)中,触发器是一种强大的工具,它可以在特定的数据库操作(如插入、更新或删除)发生时自动执行一段代码。然而,MongoDB 并没有原生内置的触发器概念。不过࿰…...
ESP8266 NodeMCU 与 Atmega16 微控制器连接以发送电子邮件
NodeMCU ESP8266 AVR 微控制器 ATmega16 的接口 Atmega16 是一款低成本的 8 位微控制器,比以前版本的微控制器具有更多的 GPIO。它具有所有常用的通信协议,如 UART、USART、SPI 和 I2C。由于其广泛的社区支持和简单性,它在机器人、汽车和自动化行业有广泛的应用。 Atmega1…...
《算法笔记》8.1小节——搜索专题->深度优先搜索(DFS)问题 C: 【递归入门】组合+判断素数
题目描述 已知 n 个整数b1,b2,…,bn 以及一个整数 k(k<n)。 从 n 个整数中任选 k 个整数相加,可分别得到一系列的和。 例如当 n4,k=3,4 个整数分别为 3,7,12…...
重生之我在学Vue--第8天 Vue 3 UI 框架(Element Plus)
重生之我在学Vue–第8天 Vue 3 UI 框架(Element Plus) 文章目录 重生之我在学Vue--第8天 Vue 3 UI 框架(Element Plus)前言一、Element Plus 基础:从安装到组件革命1.1 安装与两种引入模式全量引入(适合快速…...
从前端视角理解消息队列:核心问题与实战指南
消息队列(Message Queue)是现代分布式系统的核心组件之一,它在前后端协作、系统解耦、流量削峰等场景中发挥着重要作用。本文从前端开发者视角出发,解析消息队列的关键问题,并结合实际场景给出解决方案。 一、为什么要…...
Mysql配置文件My.cnf(my.ini)配置参数说明
一、my.cnf 配置文件路径:/etc/my.cnf,在调整了该文件内容后,需要重启mysql才可生效。 1、主要参数 basedir path # 使用给定目录作为根目录(安装目录)。 datadir path # 从给定目录读取数据库文件。 pid-file filename # 为mysq…...
Docker 安装成功后,安装 Dify 中文版本的步骤
Docker 安装成功后,安装 Dify 中文版本的步骤如下1: 克隆 Dify 代码仓库:在终端中执行以下命令,将 Dify 源代码克隆至本地环境。 bash git clone https://github.com/langgenius/dify.git进入 Dify 的 docker 目录: b…...
Spring(4)——响应相关
一、返回静态页面 1.1**RestController和Controller** 想返回如下页面: 如果我们依旧使用原来的**RestController** 可以看到的是仅仅返回了字符串。 此时将**RestController改为Controller** 可以看到这次返回的是html页面。 那么**RestController和Controller…...