2023/12/03 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <windows.h> #include <fmt/printf.h> #include <string> #include <type_traits> template <typename CharType, typename... Args> void GlobalOutputDebugString(const CharType* format, Args... args) { // 使用 fmt::sprintf 格式化字符串 …
2018/10/29 二进制编辑工具打开exe 图中可以看出程序都是由二进制数据组成
无论多么复杂的程序都只包含两部分,数据和指令。数据和指令的划分并没有明显的界限。具体取决于EIP 指令是有自己的格式。
CPU相关的指令: x86 x64 arm
硬编码就是指令集的指令
2018/03/28 win32中的宽字符 宽字符 数据类型 容器、模板 ASCII 一个字符 一个字节 GB码(扩展了的ASCII) 英文字符 一个字节 GB码 中文字符 两个字节 UNICODE字符集(unicode编码实际指的是utf-16) 常用字符 两个字节 宽字符: 用多个字节来表示的字符称之为宽字符(只要不是以单字节存储都可称为宽字符)
2018/01/12 “*”的几种用途 乘法运算符
int x = 1; int y = 2; int z = x * y;
定义新的类型
char x; char* x;
取值运算符
指针类型的变量 int* a =(int*)1; printf("%x \n",(a +1)); 10: int a =(int*)1; 00401028 mov dword ptr [ebp-4],1 11: printf("%x \n",*(a +1)); 0040102F mov eax,dword ptr [ebp-4] 00401032 mov ecx,dword ptr [eax+4] 00401035 push ecx …
2018/01/10 C语言14 指针类型 指针是C语言中的一种数据类型,
定义带 *类型的变量 char x; char* x; short y; short* y; int z; int* z; float f; float* f; double d; double* d; Student st; Student* st; 总结:
任何带有*的变量类型的标准写法:变量类型* 变量名 任何类型都可以带* 加上* 以后是新的类型,统称为“指针类型” *可以使任意多个。 指针变量赋值 char* x; char*** x; char******* x; short* ~~ int* ~~ Student* ~~ x …
2018/01/07 分析结构体大小 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 struct S1 { char c1; double d; char c2; char c3; }; struct S2 { char c1; char c2; char c3; double d; }; struct S3 { char c1; S1 s; char c2; char c3; }; 分析结构体大小 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #pragma pack(1) struct S1 { char …
2018/01/07 结构体数组的定义 类型 变量名[常量表达式]; //定义结构体类型 struct stStudent { int Age; int Level; } //定义结构体变量 struct stStudent st; //定义结构体数组 struct stStudent arr[10]; //或者 stStudent arr[10]; 结构体数组初始化 struct stStudent{ int Age; int Level; }; struct stStudent arr[5] = {{0,0},{1,1},{2,2},{3,3},{4,4}}; //或者 arr[0].Age=100; …
2018/01/07 #include char x; short y; int check() { x =1; y=2; return 0; } int main(int argc, char* argv[]) { check(); system("pause"); return 0; } //上述代码中 check 函数的反汇编 13: x =1; 00401038 C6 05 E2 55 42 00 01 mov byte ptr [x (004255e2)],1 14: y=2; 0040103F 66 C7 05 E0 55 42 00 mov word ptr [y (004255e0)],offset …
2018/01/03 思考:
当需要一个容器能够存储1个字节,你会怎么做? //char
当需要一个容器能够存储4个字节,你会怎么做? //int
当需要一个容器能够存储100个2个字节的数据,你会怎么做? //short arr[100]
当需要一个容器能够存储5个数据,这5个数据中有1字节的,2字节的有10字节的。。。你会怎么做??
2018/01/03 多维数组的定义 比如一个班有5个组,每个组有9个人
int arr[45] 或者 intarr[5*9] 或者 int arr[5][9]
比如一个县有5个学校,每个学校有3个年级,每个年级有4个班,每个班有5个组,每个组有9个人
int arr[53459] 或者int arr[5][3][4][5][9] int arr[5][3][4][5][9] ,又成为多维数组.
多维数组的初始化 int arr[3][4] = { {1,2,3,4}, {5,6,7,8}, {9,7,6,5} }; 多维数组的存储方式 int arr[3][4]; 反汇编对比
8: int arr[3*4] = …
2018/01/01 数组的定义 数组定义的格式:
数据类型 变量名[常亮]; //为什么不能使变量? //因为在声明的时候 编译器需要知道数组的长度,分配相应大小的内存 数组的初始化 方式1:
int arr[10] = {0,0,0,0,0,0,0,0,0,0};
方式2:
int arr[] = {1,2,3,4,5,6,7,8,9,10};
对应汇编
#include "stdafx.h" int main(int argc, char* argv[]) { int age[10] = {1,2,3,4,5,6,7,8,9,10}; return 0; } 8: int age[10] = …
2017/12/30 如何实现让某些语句按照一定的条件重复执行呢?
比如:打印从0 – N的值?
例子: goto语句
#include #include void MyPrint(int x) { int i = 0; B: printf("%d\n",i); i++;
2017/12/28 switch语句的定义 语法 switch(表达式) { case 常亮表达式1: 语句; break; case 常亮表达式: 语句; break; case 常亮表达式: 语句; break; ...... default: 语句; break; } 需要注意的点 表达式结束不能使浮点数 case后的值不能一样 case后的值必须是常量 break: break非常重要,当执行到一个分支后 如果没有break就会继续向下执行,遇到break才跳出switch语句 default 语句与位置无关,但是当default写在其他条件的前面时。如果没有break;,就会向下继续匹配 Switch语 …
2017/11/18 计算机只认识0和1,计算机能做的运算归根结底也就是直接对0和1做运算(通常称为 位运算)
与运算 两个位都为1时,结果为1 and(&)
或运算 只要有一个为1 就是1 or(|)
异或运算 不一样的时候是1 xor(^)
非运算(单目运算) 0变1 1变0 not(~)
左移 各二进制位全部左移若干位,高位丢弃,低位补0 shl(>) 在汇编中shr补0,sar补符号位
2017/09/21 之前可以修改EIP寄存器的指令
JMP,CALL,RETN
所有JCC指令的动作->根据标志寄存器修改EIP的值
标志寄存器 EFLAGS CF(bit 0)[Carry flag] C位 若算术产生的结果在最高有效位(most-significant bit)发生进位或者借位则将其置1 反之清零
这个标志通常用来指示无符号证书运算的溢出状态
2017/09/19 寄存器传参和堆栈传参 寄存器传参 MOV ECX,1 MOV EBX,2 CALL XX MOV EAX,ECX ADD EAX,EBX RETN 堆栈传参 –ESP寻址 PUSH 1 PUSH 2 CALL XXX MOV EAX,DWORD PTR SS:[ESP+8] //当内存中括号中包含ESP或者EBP的话 用SS ADD EAX,DWORD PTR SS:[ESP+4] RETN 8 堆栈传参 –EBP寻址 PUSH 1 PUSH 2 CALL XXX PUSH EBP MOV EBP,ESP SUB ESP,10 //提升堆栈 MOV EAX,DWORD PTR …
2017/09/19 什么是函数 函数就是一系列指令的几个,为了完成某个会重复使用的特定功能
函数调用 用JMP来执行函数 用CALL来执行函数 函数的参数和返回值 通常情况下,会将函数的计算结果放到EAX寄存器中
EAX 通常用来放返回值
简单的加法函数
ADD ECX,EDX //传参 MOV EAX,ECX //传结果到EAX中 RETN 堆栈传参 如果参数很多怎么办?10个数相加
2017/09/17 EIP寄存器 EIP寄存器表示CPU下次执行的位置
JMP指令 JMP指令相当于给EIP寄存器赋值
JMP后面只能是32位的
指令格式:
MPV EIP,寄存器/立即数/内存
简写:JMP 寄存器/立即数/内存
JMP 0x00FF19 -> MOV EIP,0X00FF19 JMP EAX -> MOV EIP,EAX JMP DWORD PTR DS:[0x18ffa0] ->MOV EIP,DWORD PTR DS:[0x18ffa0] #这里内存指针只能用32位的 CALL指令 PUSH下一行地址
MOV EIP,立即数/寄存器/内存
简写 CALL 立即数/寄存器/内存
2017/09/17 什么是堆栈 程序启动的时候操作系统会给每个程序一块虚拟的4G内存当程序需要使用的时候必须要和操作系统申请内存
堆栈是程序的心脏,程序中需要用到的重要数据,都在堆栈中体现
就是一块特殊的内存,操作系统在程序启动的时候已经分配好的,供程序执行时使用 和数据结构的堆栈无关 查看堆栈 正常内存使用从小地址往大地址使用,堆栈中从大地址往小地址使用
当堆栈用完了就会出现堆栈溢出错误
2017/09/16 寄存器数量和容量有限,为了存储大量数据,所以我们需要内存
每个程序都会有自己的独立的4GB内存空间( 这里的内存其实是虚拟的,并不是真的给了程序4G内存,当程序读或者写这段内存的时候,操作系统才会把使用的内存映射到物理内存上
物理内存和内存条之间还有一层映射