rust逆向初探
rust 逆向葵花宝典
rust逆向技巧
rust逆向三板斧:
[!NOTE]
- 快速定位关键函数 (真正的main函数):观察输出、输入,字符串搜索,断点等方法。
- 定位关键 加密区 :根据输入的flag,打硬件断点,快速捕获程序中对flag访问的位置(加密区)。
- 定位错误输出(附近一定有比较功能的程序):定位到比较位置后 提取出正确加密后的结果 。
秘诀1:一个函数在**被调试运行(F8)**之后,
如果既有输出,又要我们输入
,那么我们当前所在的函数肯定不是真正的main函数。秘诀2:所以存在flag(无论加密前后)的内存区域,都要首先打上硬件读断点 。
秘诀3:在c语言层面,对临时变量、局部变量等的修改,在汇编层面一定会反映到对内存空间的修改上。
rust语言的传参、返回值
- 前6个参数分别使用di,si,dx,cx,r8,r9,返回值使用ax寄存器:
go语言的传参、返回值
- 前6个参数,ax,bx,cx,di,si,r8 返回值 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}
相关文章:
rust逆向初探
rust 逆向葵花宝典 rust逆向技巧 rust逆向三板斧: [!NOTE] 快速定位关键函数 (真正的main函数):观察输出、输入,字符串搜索,断点等方法。定位关键 加密区 :根据输入的flag,打硬件断点,快速捕获…...
【Linux】apt 关闭 ssl 认证
【注意】apt 关闭 ssl 认证可能会引起软件安装风险,请尽量避免关闭。 执行以下命令可以实现全局关闭 sll 验证。 echo Acquire::https::Verify-Peer "false"; >> /etc/apt/apt.conf.d/99disable-signature-verificationecho Acquire::https::Verif…...
【算法】P5018 对称二叉树
题目 P5018 对称二叉树 https://www.luogu.com.cn/problem/P5018 代码 思路:领接表存储二叉树,unordered_map存储各个节点对应的值。dfs遍历一下各个子树的大小个数,再写个递归判断是否是对称二叉树,如果是就更新全局答案。 #…...
Unifying Top-down and Bottom-up Scanpath Prediction Using Transformers
Abstract 大多数视觉注意力模型旨在预测自上而下或自下而上的控制,这些控制通过不同的视觉搜索和自由观看任务进行研究。本文提出了人类注意力变换器(Human Attention Transformer,HAT),这是一个能够预测两种形式注意力…...
JavaSE(十四)——文件操作和IO
文章目录 文件操作和IO文件相关概念Java操作文件文件系统操作文件内容操作字节流FileOutputStreamFileInputStream代码演示 字符流FileWriterFileReader代码演示 缓冲流转换流 案例练习 文件操作和IO 文件相关概念 文件 通常指的是包含用户数据的文件,如文本文件、…...
【视觉SLAM】4b-特征点法估计相机运动之PnP 3D-2D
文章目录 0. 前言1. PnP求解1.1 直接线性变换DLT1.2 P3P1.3 光束平差法BA2. 实现0. 前言 透视n点(Perspective-n-Point,PnP)问题是计算机视觉领域的经典问题,用于求解3D-2D的点运动。换句话说,当知道 N N N个世界坐标系中3D空间点的坐标以及它们在图像上的投影点像素坐标…...
android 性能分析工具(04)Asan 内存检测工具
1 Asan工具简介 1.1 Asan工具历史背景 AddressSanitizer(ASan)最初由Google开发,并作为LLVM项目的一部分。ASan的设计目的是帮助开发者检测并修复内存错误,如堆栈和全局缓冲区溢出、使用已释放的内存等,这些问题可能…...
html中select标签的选项携带多个值
搜索参考资料:SELECT标签中的选项可以携带多个值吗? 【摘抄】: 它可能有一个select选项中的多个值,如下所示。 <select id"ddlEmployee" class"form-control"> <option value"">-- S…...
Lambda表达式如何进行调试
一、概述 Java8提供了lambda表达式,方便我们对数据集合进行操作,我们使用lambda表达式的时候,是不是有这样的疑问,如何对执行过程中的中间数据进行调试呢? 二、例子 在下面的例子中,我们实现随机最多生成…...
C++ —— 剑斩旧我 破茧成蝶—C++11
江河入海,知识涌动,这是我参与江海计划的第2篇。 目录 1. C11的发展历史 2. 列表初始化 2.1 C98传统的{} 2.2 C11中的{} 2.3 C11中的std::initializer_list 3. 右值引用和移动语义 3.1 左值和右值 3.2 左值引用和右值引用 3.3 引用延长生命周期…...
HTML5好看的音乐播放器多种风格(附源码)
文章目录 1.设计来源1.1 音乐播放器风格1效果1.2 音乐播放器风格2效果1.3 音乐播放器风格3效果1.4 音乐播放器风格4效果1.5 音乐播放器风格5效果 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板,程序开发,在线开发,在线沟通 作者&…...
C++设计模式行为模式———迭代器模式中介者模式
文章目录 一、引言二、中介者模式三、总结 一、引言 中介者模式是一种行为设计模式, 能让你减少对象之间混乱无序的依赖关系。 该模式会限制对象之间的直接交互, 迫使它们通过一个中介者对象进行合作。 中介者模式可以减少对象之间混乱无序的依赖关系&…...
FFmpeg 4.3 音视频-多路H265监控录放C++开发十五,解码相关,将h264文件进行帧分隔变成avpacket
前提 前面我们学习了 将YUV数据读取到AVFrame,然后将AVFrame通过 h264编码器变成 AVPacket后,然后将avpacket直接存储到了本地就变成了h264文件。 这一节课,学习解码的一部分。我们需要将 本地存储的h264文件进行帧分隔,也就是变…...
力扣 LeetCode 104. 二叉树的最大深度(Day7:二叉树)
解题思路: 采用后序遍历 首先要区别好什么是高度,什么是深度 最大深度实际上就是根节点的高度 高度的求法是从下往上传,从下往上传实际上就是左右中(后序遍历) 深度的求法是从上往下去寻找 所以采用从下往上 本…...
如何高效实现汤臣倍健营销云数据集成到SQLServer
新版订单同步-(Life-Space)江油泰熙:汤臣倍健营销云数据集成到SQL Server 在企业信息化建设中,数据的高效集成和管理是提升业务运营效率的关键。本文将分享一个实际案例——如何通过新版订单同步方案,将汤臣倍健营销云…...
Vue3中使用:deep修改element-plus的样式无效怎么办?
前言:当我们用 vue3 :deep() 处理 elementui 中 el-dialog_body和el-dislog__header 的时候样式一直无法生效,遇到这种情况怎么办? 解决办法: 1.直接在 dialog 上面增加class 我试过,也不起作用,最后用这种…...
具身智能之Isaac Gym使用
0. 简介 Isaac Gym 是由 NVIDIA 提供的一个高性能仿真平台,专门用于大规模的机器人学习和强化学习(RL)任务。它结合了物理仿真、GPU加速、深度学习框架互操作性等特点,使得研究人员和开发者可以快速进行复杂的机器人仿真和训练。…...
【大数据学习 | Spark】spark-shell开发
spark的代码分为两种 本地代码在driver端直接解析执行没有后续 集群代码,会在driver端进行解析,然后让多个机器进行集群形式的执行计算 spark-shell --master spark://nn1:7077 --executor-cores 2 --executor-memory 2G sc.textFile("/home/ha…...
《Python制作动态爱心粒子特效》
一、实现思路 粒子效果: – 使用Pygame模拟粒子运动,粒子会以爱心的轨迹分布并运动。爱心公式: 爱心的数学公式: x16sin 3 (t),y13cos(t)−5cos(2t)−2cos(3t)−cos(4t) 参数 t t 的范围决定爱心形状。 动态效果: 粒子…...
Jmeter 如何导入证书并调用https请求
Jmeter 如何导入证书并调用https请求 通过SSL管理器添加证书文件 支持添加的文件为.p12,.pfx,.jks 如何将pem文件转换为pfx文件? 在公司内部通常会提供3个pem文件。 ca.pem:可以理解为是根证书,用于验证颁发的证…...
Python程序15个提速优化方法
目录 Python程序15个提速优化方法1. 引言2. 方法一:使用内建函数代码示例:解释: 3. 方法二:避免使用全局变量代码示例:解释: 4. 方法三:使用局部变量代码示例:解释: 5. 方…...
足球虚拟越位线技术FIFA OT(二)
足球虚拟越位线技术FIFA OT(二) 在FIFA认证测试过程中,留给VAR系统绘制越位线的时间只有90秒(在比赛中时间可能更短),那么90秒内要做什么事呢,首先场地上球员做出踢球动作,然后VAR要…...
centos7.9单机版安装K8s
1.安装docker [rootlocalhost ~]# hostnamectl set-hostname master [rootlocalhost ~]# bash [rootmaster ~]# mv /etc/yum.repos.d/* /home [rootmaster ~]# curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo [rootmaster ~]# cu…...
图像编辑一些概念:Image Reconstruction与Image Re-generation
图像编辑本质上是在“图像重建”(image reconstruction)和“图像再生成”(image re-generation)之间寻找平衡。 1. Image Reconstruction(图像重建) 定义:图像重建通常是指从已有的图像中提取信…...
【STM32】在 STM32 USB 设备库添加新的设备类
说实话,我非常想吐槽 STM32 的 USB device library,总感觉很混乱。 USB Device library architecture 根据架构图: Adding a custom class 如果你想添加新的设备类,必须修改的文件有 usbd_desc.cusbd_conf.cusb_device.c 需要…...
【Redis】Redis实现的消息队列
一、用list实现【这是数据类型所以支持持久化】 消息基于redis存储不会因为受jvm内存上限的限制,支持消息的有序性,基于redis的持久化机制,只支持单一消费者订阅,无法避免消息丢失。 二、用PubSub【这不是数据类型,是…...
# Spring事务
Spring事务 什么是spring的事务? 在Spring框架中,事务管理是一种控制数据库操作执行边界的技术,确保一系列操作要么全部成功,要么全部失败,从而维护数据的一致性和完整性。Spring的事务管理主要关注以下几点…...
Java学习笔记--数组常见算法:数组翻转,冒泡排序,二分查找
一,数组翻转 1.概述:数组对称索引位置上的元素互换,最大值数组序号是数组长度减一 创建跳板temp,进行min和max的互换,然后min自增,max自减,当min>max的时候停止互换,代表到中间值 用代码实…...
ARM 架构(Advanced RISC Machine)精简指令集计算机(Reduced Instruction Set Computer)
文章目录 1、ARM 架构ARM 架构的特点ARM 架构的应用ARM 架构的未来发展 2、RISCRISC 的基本概念RISC 的优势RISC 的应用RISC 与 CISC 的对比总结 1、ARM 架构 ARM 架构是一种低功耗、高性能的处理器架构,广泛应用于移动设备、嵌入式系统以及越来越多的服务器和桌面…...
7.STM32之通信接口《精讲》之USART通信---多字节数据收发(数据包的模式:HEX数据包和文本数据包)
根据上一节的HEX数据包的设计完成,本节将完成文本数据包的编写,(HEX数据包其实本质就是原始数据,文本数据包我么要接收到还要对照ASCll进行解析封装) 有不懂的可参考上一节的讲解!!ÿ…...
wordpress 3d标签云/竞价账户
在PHP中,数组函数 array_walk () 使用回调函数遍历数组元素。 函数语法: array_walk ( array &$array , callable $callback [, mixed $userdata NULL ] ) : bool 函数参数说明: 参数描述array必需。规定数组。callback必需。一般情况…...
seo撰写网站标题以及描述的案例/app推广拉新平台
尊敬的HR: 您好,我叫XXX,是一位有着两年java开发经验的初级java开发工程师。我自学能力强,能够迅速掌握新技术,有着良好的团队合作精神,能够与团队成员配合完成复杂的项目。 我有着深厚的java语言基础&…...
苏州市住房和城乡建设局官方网站/爱采购seo
原文:http://coolketang.com/staticCoding/5a9925ad9f54542163e2e934.html 1. 下标是访问集合、列表、序列中的元素的快捷方式,结构体、枚举和类都可以定义下标。本节课将为你演示,如何给类设置下标。 2. 首先定义一个指定名称的类。 3. 然后…...
简单的模板网站/南京怎样优化关键词排名
《精通引动APP测试实战:技术、工具和案例》1)填写项目信息2)配置项目目录和活动信息3)设计UI并实现项目布局4)Android项目的源代码实现5)AndroidManifest.xml文件讲解1)填写项目信息 新建一个安…...
上海网站建设制作公/seo关键词
一. yum是什么yum是(Yellow dog Updater, Modified)主要功能是更方便的添加/删除/更新RPM包.它能自动解决包的依赖性问题.它能便于管理大量系统的更新问题 二. yum特点1)可以同时配置多个资源库(Repository)2)简洁的配置文件(/etc/yum.conf)3)自动解决增加或删除rpm包时遇到的倚…...
网站开发岗位介绍/今天微博热搜前十名
在实现摄像头拍照功能应用之前,考虑两个风险 【1】 你的应用不是每一款android 机器都可以使用 主要原因: 摄像头拍照功能执行的过程为 应用调用android系统API-->系统API,调用底层驱动-->底层驱动驱动硬件 一般的android手机有…...