C/C++逆向:switch语句逆向分析

在逆向分析中,switch语句会被编译器转化为不同的底层实现方式,这取决于编译器优化和具体的场景。常见的实现方式包括以下几种:

①顺序判断(if-else链):

编译器将switch语句转化为一系列的if-else语句。这种方式适用于case值较少的情况。

反汇编代码表现为一系列的比较和条件跳转指令(如CMP和JNE/JE)。
每个case的值会与目标变量进行比较,匹配时跳转到对应的代码块执行。
②跳转表(jump table):

switch语句中的case值是连续或接近连续的整数时,编译器可能会生成一个跳转表。跳转表是一个包含多个指针的数组,根据目标变量的值选择跳转到不同的代码块。

反汇编时表现为读取跳转表并跳转,例如使用JMP指令配合计算偏移。
通常会看到LEA(加载有效地址)指令和JMP指令配合使用,或者使用INDIRECT JMP,根据变量值计算偏移量并跳转。
③二分查找(binary search)

case值的范围较大且稀疏时,编译器可能会生成二分查找结构。编译器会按case值排序,并生成类似于二分查找树的结构来进行高效的判断。

反汇编时表现为多个比较和有条件的跳转,通常是递归式的分支跳转。

假设有如下C代码:

switch(x) {case 1:do_case1();break;case 2:do_case2();break;default:do_default();break;
}

其汇编代码可能会有以下几种表现形式:

①顺序判断:
CMP EAX, 1
JE case1
CMP EAX, 2
JE case2
JMP default
②跳转表:
MOV EAX, [EBP+var_x]  ; 获取x的值
CMP EAX, 2            ; 检查x的范围
JA default
JMP [jump_table + EAX*4]  ; 通过x的值在跳转表中选择跳转地址

jump_table中保存了各个case的代码地址。

二分查找
CMP EAX, 2
JE case2
CMP EAX, 1
JE case1
JMP default

这种实现常见于case值不连续且较大的情况。在该文中说的三种表现方式中二分查找和顺序判断这两种方式相对应容易理解,接下去的内容就蜻蜓点水大概过一下,重点会将跳转表的表现形式做说明。

逆向分析示例

假设此时有一个简单的switch代码如下:

#include <stdio.h>
#include <stdlib.h>
​
int main() {int nFlag = 0;scanf("%d", &nFlag);switch (nFlag){case 10:printf("nFlag = 10");break;case 11:printf("nFlag = 11");break;case 12:printf("nFlag = 12");break;case 254:printf("nFlag = 254");break;case 255:printf("nFlag = 255");break;case 256:ewZ3ewsprintf("nFlag = 256");break;case 454:printf("nFlag = 454");break;case 455:printf("nFlag = 455");break;case 456:printf("nFlag = 456");break;default:break;}system("pause");return 0;
}

此时使用Visual Studio对该代码进行编译,生成exe文件,对应的编译配置为Debug-x86;

Debug-x86程序分析
静态分析:

将生成的程序载入IDA中进行静态分析

Function Window中定位到main函数:

(关于定位main函数的各种方法请查看前面的文章),接下去开始逐步对进行代码分析:

mov     [ebp+var_C], 0
lea     eax, [ebp+var_C]
push    eax
push    offset Format   ; "%d"
call    j__scanf
add     esp, 8

上述这个汇编代码片段的作用是调用scanf函数从用户那里读取一个整数,并将其存储在局部变量中。我们逐步分析这个代码:

mov [ebp+var_C], 0:这条指令将值 0 存储到局部变量 [ebp+var_C] 中,通常用于初始化变量 var_C,确保它在使用前被清零。[ebp+var_C]x86汇编中的一种内存寻址方式,用于访问栈上的局部变量。为了理解它的含义,需要了解栈帧(stack frame)和ebp寄存器在函数调用中的作用。

①当函数被调用时,系统会为这个函数在栈上分配一段内存,称为栈帧。栈帧中存储着局部变量、函数参数以及保存的寄存器值等信息。
②ebp(Base Pointer,基指针)寄存器用于标记栈帧的基地址,即函数栈帧的一个固定参考点。
③在函数调用期间,ebp 通常不会改变,函数中的局部变量和参数都可以相对于 ebp 寄存器通过偏移量进行访问。

ebp+var_C 实际上表示函数栈帧中的一个局部变量的内存地址。在函数执行时,ebp 指向栈帧的底部,局部变量通常存储在 ebp 的下方,var_C 是这个局部变量的偏移量。[ebp+var_C]:表示访问存储在ebp 基地址加上 var_C 偏移量处的内存位置的值。接着我们继续解释代码:

lea eax, [ebp+var_C]:这条指令将局部变量 var_C 的地址加载到寄存器 eax 中。lea 指令用于获取某个变量的地址,而不是变量的值,因此 eax 现在保存的是变量 var_C 的地址。

push eax:将 eax(也就是变量 var_C 的地址)压入栈中。这是为了给后续的 scanf 函数准备参数,scanf 需要知道存储输入结果的变量地址。

push offset Format:将格式字符串的地址(这里是 "%d",表示整数格式)压入栈中。这是 scanf 函数的第二个参数,用来指定输入的数据类型。

call j__scanf:调用 scanf 函数,它会根据传入的格式字符串和变量地址,从用户那里读取输入并将值存储在 var_C 中。

add esp, 8:由于之前在栈中压入了两个 4 字节的参数(格式字符串的地址和变量的地址),scanf 调用后需要通过这条指令恢复栈平衡,将栈指针 esp 增加 8,清理掉这两个参数。

这个汇编代码大致等价于以下 C 代码:

int var_C = 0;
scanf("%d", &var_C);

scanf函数调用完毕,后续代码如下:

mov     eax, [ebp+var_C]
mov     [ebp+var_D4], eax
cmp     [ebp+var_D4], 0FFh
jg      short loc_4119C2
cmp     [ebp+var_D4], 0FFh
jz      loc_411A34
mov     ecx, [ebp+var_D4]
sub     ecx, 0Ah        ; switch 245 cases
mov     [ebp+var_D4], ecx
cmp     [ebp+var_D4], 0F4h
ja      def_4119BB      ; jumptable 004119BB default case, cases 13-253; jumptable 004119F1 default case, cases 257-453
mov     edx, [ebp+var_D4]
movzx   eax, ds:byte_411AF8[edx]
jmp     ds:jpt_4119BB[eax*4] ; switch jump  

这段汇编代码的主要作用是对局部变量 var_D4 进行一系列的操作和比较,并根据比较结果跳转到不同的代码位置。我们逐步解释代码的含义:

mov eax, [ebp+var_C]:将位于 [ebp+var_C] 的值(即局部变量 var_C 的值)加载到 eax 寄存器中。

mov [ebp+var_D4], eax:将 eax 中的值(即用户输入的 var_C 的值)存储到 [ebp+var_D4],即局部变量 var_D4 中。

cmp [ebp+var_D4], 0FFh:将 var_D4 的值与 0xFF(255 十进制)进行比较。

jg short loc_4119C2:如果比较结果为 "大于"(jg,Jump if Greater),则跳转到 loc_4119C2代码如下:

loc_4119C2:                             ; CODE XREF: _main+5D↑jmov     ecx, [ebp+var_D4]     sub     ecx, 100h       ; switch 201 casesmov     [ebp+var_D4], ecxcmp     [ebp+var_D4], 0C8hja      def_4119BB      ; jumptable 004119BB default case, cases 13-253; jumptable 004119F1 default case, cases 257-453mov     edx, [ebp+var_D4]movzx   eax, ds:byte_411C04[edx]jmp     ds:jpt_4119F1[eax*4] ; switch jump

cmp [ebp+var_D4], 0FFh:再次比较 var_D4 的值与 0xFF,这与前面相同,继续进行比较。

jz loc_411A34:如果比较结果为 "相等"(jz,Jump if Zero),则跳转到 loc_411A34,代码如下。

loc_411A34:                             ; CODE XREF: _main+69↑jpush    offset aNflag255 ; "nFlag = 255"call    j__printfadd     esp, 4jmp     short def_4119BB ; jumptable 004119BB default case, cases 13-253; jumptable 004119F1 default case, cases 257-453

mov ecx, [ebp+var_D4]:将局部变量 var_D4 的值加载到 ecx 寄存器中。

sub ecx, 0Ah:将 ecx 中的值减去 0xA(十进制 10)。那么在这边为什么要减去10呢?其实在反汇编代码中,var_D4 的值被减去 0xA(10),这是与 switch-case 语句的基准值对齐的一部分优化。为了更清楚地解释这个过程,我们需要理解以下几个概念:

    在高级语言中,switch-case 语句通常用于根据不同的值跳转到不同的代码分支。当代码被编译时,编译器会尝试优化 switch-case 的实现,特别是当 case 的值范围较密集时,编译器可能会选择使用 跳转表(jump table) 来提高效率。跳转表允许程序通过索引快速跳转到对应的分支,而不是通过一系列的 if-else 或 cmp 指令逐个比较所有 case 值。跳转表的索引通常是 case 值的偏移量,因此编译器会对 switch-case 的 case 值进行某种形式的调整,使得 case 的最小值成为跳转表的起始索引。

在此处的反汇编代码中,var_D4 被减去 0xA(10),这很可能是因为 switch-case 中的 case 值范围不是从 0 开始的;很有可能此时 switch-case 语句中 case 的最小值是 10,那么减去 0xA 就将输入值与 case 的最小值对齐,使其从 0 开始索引跳转表。接着回到汇编代码:

mov [ebp+var_D4], ecx:将减法操作后的结果(ecx 中的值)存储回局部变量 var_D4

cmp [ebp+var_D4], 0F4h:比较 var_D4 的新值和 0xF4(十进制 244)。

ja def_4119BBja 是无符号大于跳转指令(Jump if Above),即如果 var_D4 的值大于 0xF4,则跳转到 def_4119BB 处执行。(这个事实上就是默认分支比较简单有兴趣可以看一下,我们的重点在下面的跳转表)

def_4119BB:                             ; CODE XREF: _main+88↑j; _main+9B↑j ...mov     esi, esp        ; jumptable 004119BB default case, cases 13-253; jumptable 004119F1 default case, cases 257-453push    offset Command  ; "pause"call    ds:__imp__systemadd     esp, 4cmp     esi, espcall    j___RTC_CheckEspxor     eax, eaxpush    edxmov     ecx, ebppush    eaxlea     edx, dword_411AC8call    j_@_RTC_CheckStackVars@8 ; _RTC_CheckStackVars(x,x)pop     eaxpop     edxpop     edipop     esipop     ebxmov     ecx, [ebp+var_4]xor     ecx, ebpcall    j_@__security_check_cookie@4 ; __security_check_cookie(x)add     esp, 0D4hcmp     ebp, espcall    j___RTC_CheckEspmov     esp, ebppop     ebpretn_main           endp

mov edx, [ebp+var_D4]:将局部变量 var_D4 的值加载到寄存器 edx 中。

!!movzx eax, ds:byte_411AF8[edx]:这条指令从地址 ds:byte_411AF8[edx] 处取出一个字节,并将其零扩展到 eax 寄存器中。

①movzx 是 "移动并零扩展"(move with zero extension),它从内存中读取一个字节并将其扩展为 32 位存储在 eax 中,确保高位被清零。
②ds:byte_411AF8[edx] 表示从数据段 ds 的偏移地址 0x411AF8 开始,通过 edx 的值作为偏移量来访问一个字节数据。
ds:byte_411AF8[edx]解释:

这个部分指的是一个基于段寄存器和偏移量的内存访问。让我们逐步解析它:

ds:这是数据段寄存器(Data Segment)。

byte_411AF8:这是一个内存地址,表示一个位于 411AF8地址处的字节变量。此时411AF8地址存放的数据如下:

byte_411AF8     db 0, 1, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4; DATA XREF: _main+94↑rdb 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ; indirect table for switch statementdb 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4db 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4db 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4db 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4db 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4db 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4db 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4db 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4db 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4db 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4db 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4db 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3

这是一个查找表用于处理 switch-case 语句。表中大多数值是 4,这可能是查找表的默认值,用于表示跳转到 switch-case 的默认分支(default case)。特定位置上,例如第一个位置是 0,第二个位置是 1,第三个位置是 2,最后一个位置是 3,这些值对应于 switch-case 语句中的有效分支。

[edx]:表示用 edx 中的值作为索引来访问该数组中的具体字节。

到此我们就可以清楚的知道ds:byte_411AF8[edx]表达的含义:表示对 byte_411AF8 数组的访问,其中 edx 寄存器中的值用作数组的索引。在获取数组的对应索引后,执行下一条指令:

!!jmp ds:jpt_4119BB[eax*4]

这条指令是一个基于跳转表的间接跳转,结合跳转表的内容来看,它是通过 eax 中的值从跳转表中选择一个跳转目标,然后执行相应的代码分支(case)。

以下为跳转表jpt_4119BB的内容,在跳转表中存储了各个 switch-case 语句的跳转地址。每一行表示一个 dd 数据(dd 表示定义双字节,4 个字节),即一个内存地址。正因为跳转表中存储的case语句的跳转地址为dd类型,所以在索引需要乘以 4 来计算跳转表的偏移量。

jpt_4119BB     dd offset loc_4119F8    ; DATA XREF: _main+9B↑rdd offset loc_411A07    ; jump table for switch statementdd offset loc_411A16dd offset loc_411A25dd offset def_4119BB

jmp ds:jpt_4119BB[eax*4]指令通过 eax 的值(在上条指令的查询表中获取)计算出的偏移量,跳转到跳转表中指定的地址。

例如,此时程序接收到的用户输入为254,此时我们根据代码做一个解析(解析放在注释~~~部分):

mov     eax, [ebp+var_C]                          ~~~程序接收到254~~~
mov     [ebp+var_D4], eax
cmp     [ebp+var_D4], 0FFh
jg      short loc_4119C2
cmp     [ebp+var_D4], 0FFh
jz      loc_411A34
mov     ecx, [ebp+var_D4]
sub     ecx, 0Ah        ; switch 245 cases        ~~~254-10 = 244~~~
mov     [ebp+var_D4], ecx
cmp     [ebp+var_D4], 0F4h
ja      def_4119BB      ; jumptable 004119BB default case, cases 13-253; jumptable 004119F1 default case, cases 257-453
mov     edx, [ebp+var_D4]               ~~~244 => edx~~~~
movzx   eax, ds:byte_411AF8[edx]        ~~~以edx(244)为索引在查询表byte_411AF8中查询~~~
jmp     ds:jpt_4119BB[eax*4] ; switch jump          ~~~根据查询到的值在跳转表中做跳转~~~

这个时候我们来说以下程序以edx(244)为索引在查询表byte_411AF8中查询的结果:

查询到的结果为3;接着执行jmp ds:jpt_4119BB[eax*4]进行跳转(间接跳转),此时的跳转指令为jmp ds:jpt_4119BB[12],对照跳转表:

我们最后会跳转进入loc_411A25分支,此时该分支代码如下:

loc_411A25:                             ; CODE XREF: _main+9B↑j; DATA XREF: .text:jpt_4119BB↓opush    offset aNflag254 ; jumptable 004119BB case 254call    j__printfadd     esp, 4jmp     short def_4119BB ; jumptable 004119BB default case, cases 13-253; jumptable 004119F1 default case, cases 257-453

成功定位跳转至case 254分支并执行代码;其他根据查询表、跳转表进行跳转的分支跳转也是按照这个流程,这边就不再做其他赘述了。

动态分析

x86-Debug程序载入x86dbg中,进行动态分析:

右击汇编代码窗口,选择搜索->所有模块->字符串输入特征字符串(nFlag)定位到main函数,并开始分析:

此时持续按F8进行步过运行程序,直到运行到如下函数后就无法继续运行:

此时打开程序窗口可以看到此时程序正在等待用户输入,这个时候基本上可以断定switchre_x86-debug.4D10A0函数为scanf函数;存放用户输入的变量地址存放在eax寄存器中,此时输入254为例子查看程序的具体执行。

回车后程序继续执行;在接收到用户输入的数据后先与0xFF(255)进行比较:若大于255则跳转至switchre_x86-debug.4D19C2位置,若等于0xFF则跳转至switchre_x86-debug.4D1A34位置。(这些都比较简单,如果感觉看着吃力的话可以再去看看笔者之前的文章这边我们的重点还是放在Switch分支结构的跳转表表现形式)

因为此时我们输入的值为254所以既不大于也不等于0xFF(x64dbg可以在程序运行过程中修改内存中变量的值),接着运行以下指令。

将用输入的值传入ecx寄存器,接着减去A(10);接着与0xF4(244)进行比较,大于244则转入switchre_x86-debug.4D1A7D(默认分支),若不大于则将被减去10的用户输入数据转入edx;此时我们可以在寄存器窗口查看当前寄存器中的值。

接着进行地址索引(间接跳转),索引得到的值:0xF4+4D1AF8 = 4D1BEC此时我们地址索引的代码如下:

这个时候我们可以直接在内存窗口,输入ctrl + G进行值的查看;

可以看到此时内存中的值为03,其实从代码中我们也可以发现,程序会将地址索引到的值放入eax寄存器中:此时也可以查看寄存器窗口eax寄存器中的值为3:

接着查看下面的代码:最后执行jmp跳转指令,此时会进行地址索引(其实就是间接跳转),获取最后case的执行地址。

这个时候我们接着计算地址:(eax)3*4 + 4D1AE4 = 4D 1AF0(该地址是存储case代码地址的内存地址),我们接着在内存窗口中查看地址为4D 1AF0的值,因为是小端序存储,所以得到的值应该是:004D1A25。

这个地址就是case对应的地址位置,我们在汇编窗口进行定位,可以看到此时已经跳转至case 254分支。

其他的分支也是如此,此处就不做过多说明。

在本篇文章中,我们深入探讨了 switch-case 语句在汇编代码中的表现形式,特别是如何通过跳转表来优化分支跳转逻辑。通过分析具体的反汇编代码,我们能够清晰地理解编译器如何通过查找表和间接跳转提高执行效率。

间接跳转是一种程序控制流机制,它通过一个变量(通常是寄存器或内存地址)中的值来决定程序的跳转目标,而不是直接跳转到一个明确指定的地址。与直接跳转不同,间接跳转的目标地址是在程序运行时动态确定的。

这不仅帮助我们更好地理解反汇编代码中的结构,也为我们逆向分析复杂程序提供了重要的工具和思路。希望通过这些案例,你能够对 switch-case 语句的反汇编分析有更加深入的理解。此外x64-release程序的逆向过程也与x86-debug相似,只不过release代码中有对程序进行优化,有兴趣也可以动手做做。

另外,请多多关注笔者的VX-公ZH-【风铃Sec】,你们的支持就是我更新的动力!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1543002.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

管道物体计数系统源码分享

管道物体计数检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

信创背景下中职计算机组装与维护课程教学解决方案

在当前的国际形势下&#xff0c;确保信息化系统的安全性和可靠性显得尤为重要。为了提高信息技术的安全性和可靠性&#xff0c;国家鼓励并支持使用国产的信息技术、工具和资源来替代现有的技术体系。这一过程被称为“安全可信的创新替代”&#xff0c;它已经成为国家安全战略的…

VMware ESXi 8.0U3b macOS Unlocker OEM BIOS 2.7 标准版和厂商定制版

VMware ESXi 8.0U3b macOS Unlocker & OEM BIOS 2.7 标准版和厂商定制版 ESXi 8.0U3 标准版&#xff0c;Dell (戴尔)、HPE (慧与)、Lenovo (联想)、Inspur (浪潮)、Cisco (思科)、Hitachi (日立)、Fujitsu (富士通)、NEC (日电) 定制版、Huawei (华为) OEM 定制版 请访问…

OpenResty安装及使用

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

构建高可用和高防御力的云服务架构第四部分:REDIS(4/5)

本文的目的是深入探讨Redis在构建高可用和高防御力云服务架构中的应用。我们将分析Redis的工作原理、核心特性以及如何通过Redis优化云服务架构的性能和安全性。此外&#xff0c;我们还将提供实际案例和最佳实践&#xff0c;帮助读者更好地理解和应用Redis&#xff0c;以构建更…

中小企业体系技术抽象沉淀-异地灾备篇

IT团队内部使用工具 系列文章&#xff1a;https://blog.csdn.net/caicongyang/article/details/136857045 DDL DML管控 https://github.com/hhyo/Archery/ flyway 文档编写 wiki 技术对外输出文档推荐gitbook 同城双活数据同步方案 总览&#xff1a; vivo 系列文章&#x…

普通程序员如何快速入门AIGC

文章目录 第1阶段&#xff1a;基础知识打牢 (1-2周)第2阶段&#xff1a;深度学习理论与实践 (2-4周)第3阶段&#xff1a;AIGC 生成技术入门 (3-5周)第4阶段&#xff1a;进阶学习和项目实战 (5-8周)第5阶段&#xff1a;保持学习和更新 (持续进行) 要快速入门 AIGC&#xff08;AI…

SPI驱动学习六(SPI_Master驱动程序)

目录 前言一、SPI_Master驱动程序框架1. SPI传输概述1.1 数据组织方式1.2 SPI控制器数据结构 2. SPI传输函数的两种方法2.1 老方法2.2 新方法 二、如何编写SPI_Master驱动程序1. 编写设备树2. 编写驱动程序 三、SPI_Master驱动程序简单示例demo1. 使用老方法编写的SPI Master驱…

Webrtc开发实战系列 - win10+vs2022下编译最新webrtc代码

1. 准备起步 操作系统&#xff1a;windows 10 安装 vs2019/vs2022 安装 win10 sdk 19041 一定勾选 Debugging Tools for Windows 科学上网准备代理工具 磁盘剩余空间至少 30G 推荐用一台干净的机器或者虚拟机来编译WebRTC&#xff0c;安装过python的会出现一些非常棘手…

昂首资本:欧美货币对的交易智慧

在外汇市场的海洋中&#xff0c;昂首资本的投资者们深知&#xff0c;把握欧美货币对的交易时段是获取收益的关键。欧美货币对&#xff0c;即欧元对美元&#xff0c;因其在欧洲和美国市场的活跃交易时段而备受瞩目。这两个时段不仅交易量巨大&#xff0c;而且价格波动剧烈&#…

【隐私计算篇】利用多方安全计算MPC实现VGG16人脸识别隐私推理

1. 背景介绍 本文主要介绍一种利用多方安全计算MPC技术&#xff0c;实现VGG16的人脸识别模型&#xff0c;侧重于模型推理阶段&#xff0c;目前已经公开专利&#xff0c;因此以下内容的分享都是基于公开材料。该分享涉及到最小化多方安全计算(MPC)以及明密文混合计算的思想&…

JAVA开源项目 甘肃非物质文化网站 计算机毕业设计

本文项目编号 T 043 &#xff0c;文末自助获取源码 \color{red}{T043&#xff0c;文末自助获取源码} T043&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

python画图|把X轴标签移动到图像顶端

在前述学习过程中&#xff0c;我们一直使用的是默认的轴坐标&#xff0c;X轴往往置于图像的下端。 有时候&#xff0c;也会有将X轴标签放置在图形顶端的需求&#xff0c;今天就一起学习一下。 【1】官网教程 首先打开官网&#xff0c;可以通过下述链接一步直达&#xff1a; …

软考高级:系统安全 -区块链特点:去中心化、开放性、自治性、安全性、匿名性

讲解 生活化例子 想象一下&#xff0c;你和朋友们玩一个共享账本的游戏。每个人都可以在账本上记账&#xff0c;没人可以单独改动账本&#xff0c;大家都可以随时查看账本内容&#xff0c;也不用再信任某个单独的人来管理账本。这就类似于区块链的工作原理。 概念讲解 去中…

基于c++实现的简易shell

代码逻辑 核心思想 解析命令行&#xff0c;拆解命令及其选项创建子进程&#xff0c;在子进程中执行命令如果是前台执行命令&#xff0c;则父进程就阻塞等待子进程中命令执行结束后回收子进程的资源如果是后台执行命令&#xff0c;则父进程不进行阻塞等待&#xff0c;可继续向下…

【机器学习】---神经架构搜索(NAS)

这里写目录标题 引言1. 什么是神经架构搜索&#xff08;NAS&#xff09;1.1 为什么需要NAS&#xff1f; 2. NAS的三大组件2.1 搜索空间搜索空间设计的考虑因素&#xff1a; 2.2 搜索策略2.3 性能估计 3. NAS的主要方法3.1 基于强化学习的NAS3.2 基于进化算法的NAS3.3 基于梯度的…

【数据结构】图的遍历

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《C游记》《进击的C》《Linux迷航》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、深度优先遍历1.1 定义1.2 实现 二、广度优先遍历2.1 定义2.2 实现 三、DFS与BFS的对比 引言 前置知识&…

linux用户管理运行级别找回root密码

目录 1.用户的添加 1.1用户添加的基本指令 1.2不指定家目录的名称 1.3指定家目录的名称 2.密码的修改 3.删除目录 3.1删除的两个情况 3.2删除的流程 4.查询用户的信息 5.用户的切换 6.用户组 6.1用户组的概念 6.2创建用户到指定的组 6.3修改用户到其他的组 6.4用…

SpringCloud Alibaba之Sentinel实现熔断与限流

&#xff08;学习笔记&#xff09; QPS&#xff08;Query Per Second&#xff09;&#xff1a;即每秒查询率&#xff0c;是对⼀个特定的查询服务器在规定时间内所处理流量多少的衡量标准。QPS req/sec 请求数/秒&#xff0c;即每秒的响应请求数&#xff0c;也即是最⼤吞吐能⼒…

ATTCK实战系列-Vulnstack三层网络域渗透靶场(一)

ATT&CK实战系列-Vulnstack三层网络域渗透靶场&#xff08;一&#xff09; 一、环境搭建1.1 靶场拓扑图1.2 靶场下载链接1.3 虚拟机配置1.3.1 Windows 7 (web服务器)1.3.2 Windows 2008 (域控)1.3.3 Win2k3 (域内主机) 二、外网打点突破2.1 信息搜集2.2 phpmyadmin 后台 Get…