辗转相除法
欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数。
其计算原理依赖于下面的定理:定理:divi(a, b) = divi(a, a%b)
###计算机--迭代的思想--递归
//辗转相除法
int divi_1(int a, int b)
{
int divi = 0;
while (a%b)
{
divi = a % b;
a = b;
b = divi;
}
divi = b;
return divi;
}
使用取余和除法操作来反转整数
主要过程--使用数学方法 以及关于溢出的判断
// 弹出 x 的末尾数字 digit
digit = x % 10
x /= 10
// 将数字 digit 推入 rev 末尾
rev = rev * 10 + digit
###示例代码 假设环境不允许存储 64 位整数(有符号或无符号)
class Solution {
public int reverse(int x) {
int rev = 0;
while (x != 0) {
//判断溢出,因为输入的是32位的有符号整数 x
//即输入的 -2147483648<=x<=2147483647
//所以翻转后的最后一位是1或2并不会导致溢出
//因此只需判断九位数 > int.MaxValue / 10 或者 < int.MinValue / 10
if (rev < Integer.MIN_VALUE / 10 || rev > Integer.MAX_VALUE / 10) {
return 0;
}
int digit = x % 10;
x /= 10;
rev = rev * 10 + digit;
}
return rev;
}
}
#### 按照字符串进行处理
实现字符串反转,包括 切片、reversed()、循环、递归、模拟栈操作等
遍历 :
使用 for 循环遍历 使用 for 循环和 range() 在遍历列表 使用列表推导式遍历列表
使用 while 循环遍历
使用 enumerate() 方法遍历列表 使用 zip() 遍历列表
使用 map() 和 lambda 遍历列表 使用迭代器 iter() 和 next() 遍历列表
方法:切片-- 使用reversed()方法 模拟出栈pop()
方法3:使用while循环
方法4:使用for循环字符串拼接
方法5:使用递归
len()
数据结构:
语言对字符串提供了 split(拆分),reverse(翻转)和 join(连接)等方法,
python :
a = '123456789'
print(a[::-1]) # 利用字符串下标倒序输出
print(''.join(reversed('123456789')))
def reverse_string(str):
l_str = list(str) # 模拟全部入栈
new_string = ""
while len(l_str)>0:
new_string += l_str.pop() # 模拟出栈
return new_string
使用list循环获取,再转换成字符串类型
def reverse_string_list(str):
str_lis = [] # 定义空列表
index = len(str) # 字符串长度
# 在str字符穿长度内执行循环语句,实现倒序输出
while index:
index -= 1
str_lis.append(str[index]) # 将下标对应值输出到空列表str_lis中
return ''.join(str_lis)
def reverse_string(str):
l = len(str)
x=""
for i in range(l-1,-1,-1):
x += str[i]
return x
def reverse_string(s):
if len(s) == 1: # 判断字符串长度是否只含有一位数字,若是直接返回,本身即为反转后的字符串
return s
str = s[-1] + reverse_string(s[:-1]) # 利用递归实现
return str
C++遍历
### for 循环遍历
数组指针 指针等
### while 循环遍历
### range for_each
for (auto& i: a){ // auto能够自动推导变量类型,引用类型除外
### 迭代器
for(auto i = begin(a); i != end(a); i++){ // 成员函数begin()和end()来获取遍历开始地址和遍历结束地址,同时,迭代器使用之后会自动回收
###高阶
std::transform
###遍历算法
-深度优先遍历;3-广度优先遍历
###C++反转字符串
C++标准库提供了一个名为std::reverse的函数,可以直接对字符串进行反转
使用递归
使用循环
std::string reverseString(const std::string& str) {
std::string reversedStr;
for (int i = str.length() - 1; i >= 0; i--) {
reversedStr += str[i];
}
return reversedStr;
}
std::string reverseString(const std::string& str) {
if (str.length() <= 1) {
return str;
}
return reverseString(str.substr(1)) + str[0];
}
###使用头尾帧交换的方式
双指针法,我们定义两个指针(也可以说是索引下标),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素
class Solution {
public:
void reverseString(vector<char>& s) {
// 1.库函数:
//reverse(s.begin(), s.end());
// 2.双指针交换:
for (int i = 0, j = s.size() - 1; i < j; i++, j--) {
swap(s[i], s[j]);
}
}
};
在遍历字符串的过程中,只要让 i += (2 * k),i 每次移动 2 * k 就可以了,然后判断是否需要有反转的区间。
不用一个一个字符计数判断。
class Solution {
public:
string reverseStr(string s, int k) {
for (int i = 0; i < s.size(); i += (2 * k)) {
// 1. 每隔 2k 个字符的前 k 个字符进行反转
// 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
if (i + k <= s.size()) {
reverse(s.begin() + i, s.begin() + i + k );
} else {
// 3. 剩余字符少于 k 个,则将剩余字符全部反转。
reverse(s.begin() + i, s.end());
}
}
return s;
}
};
应用--叠帧的场景
def reverseStr(timestamps_ls,step,ignore_num)
cur_idex =0
K = len(timestamps_ls)
while(cur_index < K):
target_ts = timestamps_ls[cur_idex]
selectd = range(max(0,cur_idex),min(cur_idex+step,K))
cur_idex += step
ts_wind = [timestamps_ls[s] for s in selectd]
if len(ts_wind) >= ignore_num:
for i,ts in enumerate(ts_wind):
pass
else:
break
def reverseStr(timestamps_ls,step,ignore_num)
cur_idex =0
K = len(timestamps_ls)
for( cur_idex = 0; cur_idex < K; cur_idex += step )
target_ts = timestamps_ls[cur_idex]
selectd = range(max(0,cur_idex),min(cur_idex+step,K))
ts_wind = [timestamps_ls[s] for s in selectd]
if len(ts_wind) >= ignore_num:
for i,ts in enumerate(ts_wind):
pass
else:
break
while循环是在进入循环之前
先判断条件是否满足,
如果条件为真,则执行循环体;
如果条件不满足,则整个循环体一次都不执行。
而do-while循环是
先执行一次循环体,
然后再判断条件是否满足,只有在条件为真的情况下,才会继续执行后续的循环体,
否则结束循环
while循环:需要手动定义和管理循环变量的状态
for 循环
for(单次表达式;条件表达式;末尾循环体)
{中间循环体;}
逆向工程
分析二进制文件:
使用逆向工程工具打开应用程序的二进制文件,进行分析。可以查看函数、变量、控制流等信息,理清应用程序的逻辑结构。
反汇编代码:
对应用程序的二进制代码进行反汇编,将其转换成汇编代码进行分析。可以查看应用程序的底层执行逻辑,找出其中的漏洞或隐藏的功能。
调试应用程序:
使用调试器如GDB对应用程序进行调试,可以逐步执行代码并查看寄存器、内存等信息,帮助理解程序的行为。
动态分析:
通过动态分析可以在运行时跟踪应用程序的执行过程,监视其行为并分析其运行时状态。可以使用工具如strace、ltrace等进行API调用和库函数跟踪。
修改和重构代码:
通过逆向工程可以了解应用程序的内部结构和逻辑,可以对其进行修改和重构,实现定制化功能或漏洞修复。
在Linux环境下进行C++应用的逆向工程通常可以通过以下步骤来实现:
使用逆向工程工具:在Linux下有许多强大的逆向工程工具可供选择,如IDA Pro、Ghidra、Radare2等
这些工具能够帮助分析和反汇编应用程序的二进制代码,还可以进行静态和动态分析。
readelf, objdump, ldd, xxd,hexdump, dd, strace,
2 使用ldd探索依赖性
3 使用xxd查看文件内容
4 使用readelf解析并提取ELF库文件
5 使用nm解析符号 C++编译器提出了符号修饰(mangled name)。符号修饰实质上是原始函数名称与函数参数编码的组合。这样,函数的每个版本都会获得唯一的名
6 使用strings查看Hints
7 使用strace和ltrace跟踪系统调用和库文件调用
8 使用 objdump 检查指令集行为
9 使用GDB转储动态字符串缓冲区
GNU binutils (配合gcc工作)
GNU coreutils coreutils【对应的嵌入式场合,主要是 busybox 】
汇编语句
二进制指令是一样的
JE(Jump if Equal)、JNE(Jump if Not Equal)、JG(Jump if Greater)、JL(Jump if Less)
x86_64架构下的CPU有两种主要的汇编风格: Intel风格和AT&T风格。
支持Intel汇编风格的操作系统主要是Windows,
支持AT&T汇编风格的操作系统主要是Unix以及Unix-like操作系统
AT&T汇编是从左向右执行 mov %ax, %bx 寄存器前面有一个% 字面量前面都有一个$
Intel汇编是从右往左执行 mov bx, ax
控制转移包括jump、call、ret
编译过程
-g -g可执行程序包含调试信息 为了调试用的 加个-g 是为了gdb 用,不然gdb用不到
-c 只编译不链接 产生.o文件,就是obj文件,不产生执行文
-Wall 选项意思是编译后显示所有警告
在CMakeLists.txt 中
add_definitions("-Wall -g")
set(CMAKE_BUILD_TYPE "Debug")
obj objdump 用来显示一个或者多个目标文件的信息
-d:将代码段反汇编
-S:将代码段反汇编的同时,将反汇编代码和源代码交替显示,编译时需要给出-g,即需要调试信息
objdump -S -C -d a.out
参考
反转字符串——Python笔试题干货 https://blog.csdn.net/qq_39312119/article/details/135343897
C/C++逆向:循环语句逆向分析 https://blog.csdn.net/WolvenSec/article/details/142535149