程序片段(01):define.h+data.h&data.c+control.h&control.c+view.h&view.c+AI.h&AI.c+main.c
内容概要:迷宫游戏
///define.h
//通用工具
#include <stdio.h>
#include <stdlib.h>
#define N 10
///data.h
//迷宫布局
#include "define.h"//对外声明全局变量
extern int realPath[N][N];//软件工程规范建议使用extern关键字(可有/可无)
extern int AIPath[N][N];
extern int startPointX;
extern int startPointY;
extern int endPointX;
extern int endPointY;
extern int successPath;
///data.c
//存储数据
#include "define.h"
int realPath[N][N] = {//真实路径
{ 1, 0, 2, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 2, 0, 0, 2, 0, 0, 0 },
{ 0, 0, 0, 2, 0, 0, 2, 0, 0, 0 },
{ 0, 0, 0, 0, 2, 0, 0, 2, 2, 0 },
{ 0, 0, 0, 0, 2, 0, 2, 0, 0, 0 },
{ 0, 0, 0, 0, 2, 0, 0, 0, 0, 2 },
{ 2, 2, 2, 0, 0, 2, 0, 2, 0, 0 },
{ 0, 0, 0, 0, 0, 2, 0, 2, 0, 2 },
{ 0, 0, 0, 0, 0, 0, 0, 2, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0 }
};
int AIPath[N][N] = {//智能路径
{ 1, 0, 2, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 2, 0, 0, 2, 0, 0, 0 },
{ 0, 0, 0, 2, 0, 0, 2, 0, 0, 0 },
{ 0, 0, 0, 0, 2, 0, 0, 2, 2, 0 },
{ 0, 0, 0, 0, 2, 0, 2, 0, 0, 0 },
{ 0, 0, 0, 0, 2, 0, 0, 0, 0, 2 },
{ 2, 2, 2, 0, 0, 2, 0, 2, 0, 0 },
{ 0, 0, 0, 0, 0, 2, 0, 2, 0, 2 },
{ 0, 0, 0, 0, 0, 0, 0, 2, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0 }
};
int startPointX = 0;//起始点
int startPointY = 0;
int endPointX = 9;//终止点
int endPointY = 9;
int successPath = 0;//标识通路
///control.h
//迷宫控制
#include "data.h"
void operateMaze(char operate);
///control.c
//数据处理
#include "control.h"
#include "view.h"
void operateMaze(char operate)//操作迷宫
{
switch (operate)
{//移动起始点
case 'w':
if (-1 < startPointX - 1 && 2 != realPath[startPointX - 1][startPointY])
{//操作真实路径
realPath[startPointX][startPointY] = realPath[startPointX][startPointY] ^ realPath[startPointX - 1][startPointY];
realPath[startPointX - 1][startPointY] = realPath[startPointX][startPointY] ^ realPath[startPointX - 1][startPointY];
realPath[startPointX][startPointY] = realPath[startPointX][startPointY] ^ realPath[startPointX - 1][startPointY];
--startPointX;
}
break;
case 's':
if (10 > startPointX + 1 && 2 != realPath[startPointX + 1][startPointY])
{
realPath[startPointX][startPointY] = realPath[startPointX][startPointY] ^ realPath[startPointX + 1][startPointY];
realPath[startPointX + 1][startPointY] = realPath[startPointX][startPointY] ^ realPath[startPointX + 1][startPointY];
realPath[startPointX][startPointY] = realPath[startPointX][startPointY] ^ realPath[startPointX + 1][startPointY];
++startPointX;
}
break;
case 'a':
if (-1 < startPointY - 1 && 2 != realPath[startPointX][startPointY - 1])
{
realPath[startPointX][startPointY] = realPath[startPointX][startPointY] ^ realPath[startPointX][startPointY - 1];
realPath[startPointX][startPointY - 1] = realPath[startPointX][startPointY] ^ realPath[startPointX][startPointY - 1];
realPath[startPointX][startPointY] = realPath[startPointX][startPointY] ^ realPath[startPointX][startPointY - 1];
--startPointY;
}
break;
case 'd':
if (10 > startPointY + 1 && 2 != realPath[startPointX][startPointY + 1])
{
realPath[startPointX][startPointY] = realPath[startPointX][startPointY] ^ realPath[startPointX][startPointY + 1];
realPath[startPointX][startPointY + 1] = realPath[startPointX][startPointY] ^ realPath[startPointX][startPointY + 1];
realPath[startPointX][startPointY] = realPath[startPointX][startPointY] ^ realPath[startPointX][startPointY + 1];
++startPointY;
}
break;
default:
break;
}
showMaze(realPath);
}
///view.h
//迷宫展示
#include "data.h"
void showMaze(int maze[N][N]);//显示迷宫
///view.c
//数据显示
#include "view.h"
void showMaze(int maze[N][N])
{
printf("------------------------------------
");
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < N; ++j)
{
printf("%2d", maze[i][j]);
}
printf("
");
}
printf("
");
}
///AI.h
//迷宫智能
#include "control.h"
int AIFindWay(int AIPath[N][N], int startPointX, int startPointY);//智能寻路
void AIMazeMove();//智能迷宫移动
///AI.c
//人工智能
#include "AI.h"
int AIFindWay(int AIPath[N][N], int startPointX, int startPointY)
{
if (endPointX == startPointX && endPointY == startPointY)
//测试假定起始点是否已经到达终点位置
//printf("能够形成迷宫通路!
");
return successPath = 1;//标识成功找到一条通路,但不并不一定就是一条最短路径(相当于深度遍历优先原理)
int movePointX = startPointX;//假定起始点作为移动点,能够走出一条迷宫通路-->由于这里使用的是全局变量,所以,不采取局部变量,但是这样便于理解
int movePointY = startPointY;
AIPath[movePointX][movePointY] = 3;//试探:标识活路->已寻访路线标识,,防止回头路
//假定终点在右下角的最佳遍历方式:右->下->左->上
if (0 == successPath && 10 > movePointY + 1 && 2 != AIPath[movePointX][movePointY + 1]) AIFindWay(AIPath, movePointX, movePointY + 1);
if (0 == successPath && 10 > movePointX + 1 && 2 != AIPath[movePointX + 1][movePointY]) AIFindWay(AIPath, movePointX + 1, movePointY);
if (0 == successPath && -1 < movePointY - 1 && 2 != AIPath[movePointX][movePointY - 1]) AIFindWay(AIPath, movePointX, movePointY - 1);
if (0 == successPath && -1 < movePointX - 1 && 2 != AIPath[movePointX - 1][movePointY]) AIFindWay(AIPath, movePointX - 1, movePointY);
if (0 == successPath)//回溯:标识死路
AIPath[movePointX][movePointY] = 0;
return 0;//用于判断迷宫是否含有出口
}
void AIMazeMove()
{
AIPath[0][0] = 1;//标识:迷宫起始点
while (endPointX != startPointX && endPointY != startPointY)
{
if (10 > startPointY + 1 && 3 == AIPath[startPointX][startPointY + 1])
{
AIPath[startPointX][startPointY + 1] = 0;//防止寻路迷宫的回走现象
operateMaze('d');
}
else if (10 > startPointX + 1 && 3 == AIPath[startPointX + 1][startPointY])
{
AIPath[startPointX + 1][startPointY] = 0;
operateMaze('s');
}
else if (-1 < startPointY - 1 && 3 == AIPath[startPointX][startPointY - 1])
{
AIPath[startPointX][startPointY - 1] = 0;
operateMaze('a');
}
else if (-1 < startPointX - 1 && 3 == AIPath[startPointX - 1][startPointY])
{
AIPath[startPointX - 1][startPointY] = 0;
operateMaze('w');
}
}
}
///main.c
//接口调用
#include "view.h"
#include "AI.h"
int main(void)
{
//showMaze(realPath);//显示初始情况
//while (1)
//{
// char ch = getchar();
// getchar();
// operateMaze(ch);
// showMaze(realPath);
//}
int successPath = AIFindWay(AIPath, 0, 0);
if (0 == successPath)
printf("不可以走出!
");
else
{
printf("可以走出!
");
showMaze(AIPath);
AIMazeMove();
}
system("pause");
}
程序片段(02):main.c
内容概要:GccArray
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("Hello world!
");
int num=10;
scanf("%d",&num);
int a[num];//GCC可以动态分配数组
//动态分配,运行的时候
return 0;
}
程序片段(03):指针.c+go.c
内容概要:指针预热
///指针.c
#include <stdio.h>
#include <stdlib.h>
//01.指针变量内容简介:
// 1.指针变量概念:
// (1).特殊的变量:存储的是具备地址含义的数据,而非普通的数据
// (2).指针变量和普通变量同样位于内存当中,属于同样的栈内存存储(一般情况)
// 2.指针所涉及的运算符:
// 取地址运算符&:
// 根据内存实体获取该数据实体所在的内存地址
// 指针运算符:
// 声明时期:
// 标识指针变量,标识所声明的变量不是普通变量,而是具备存储地址意义的变量
// 使用时期:
// 根据内存实体的地址获取该数据实体本身,以用于直接操作该数据实体
// 注意事项:
// 1.数据区与代码区的概念不同
// 2.查看多个变量需要多个内存图解
// 3.通常所说的指针指的是指针变量
// 4.严格意义上指针变量,指针,地址的意义不同:
// 指针变量:是一个具有存储地址含义的变量
// 指针:具备类型意义的地址
// 地址:仅仅只有一个数值的含义
int main01(void)
{
int num = 10;
printf("%p
", &num);//取地址运算符&-->获取地址
*(&num) = 3;//指针运算符*-->声明指针+根据地址获取内容
//&num = 0x123;//取地址运算符&num所执行的操作位于寄存器,C语言无法直接给寄存器进行赋值操作
printf("%d
", num);
system("pause");
}
//02.指针变量:
// 1.区分直接赋值与间接赋值:
// 直接赋值:直接操作变量本身,也就是内存实体(数据实体)本身
// 间接赋值:通过指针变量(存储普通变量所属地址的变量)间接操作内存实体(数据实体)本身
// 2.使用指针变量的意义:
// 间接的操作内存实体(数据实体)本身
int main02(void)
{
int num = 10;
//num = 4;//直接赋值
int * numP = #//pNum是一个指针变量(地址变量)
printf("%p
", numP);//打印指针变量所存储的具备地址含义的数值,也就是普通变量的地址-->一级指针含义
printf("%p
", &numP);//打印指针变量的地址-->二级指针含义
*numP = 13;//间接赋值:给以指针变量numP的数据为地址的变量间接赋值
system("pause");
}
//03.关于跨进程内存访问:
// 普通方式:
// 一个进程不可以直接访问另外一个进程的所属内存空间
// 特殊方式:
// 1.通过模块儿注入的方式可以实现模块儿访问进程内存
// 2.权限提升的方式也可以事项跨进程内存访问
int main03(void)
{
int *p = 0xAE0720;
*p = 32;//一个进程不可以随便读写另外一个进程的所属内存
system("pause");
}
///go.c
#include <Windows.h>
//01.通过模块儿注入方式:
// 1.实现类似于跨进程的内存访问
// 2.自动化的模块儿注入技术
// 注:一定要防止进程内部死循环,以免进程卡顿现象严重(CPU占用厉害),
// 因此需要进行休眠状态切换(调度CPU执行权)
_declspec(dllexport) go()
{
int * p = (int *)0x20671290;//通过模块儿实现模块儿修改进程所属内存的某个内存空间
*p = 80;//访问以指针变量p的值为地址的内存实体(数据实体)
while (1)
{
if (*p < 9000)
*p = 9000;
Sleep(100);//防止进程卡死
}
}
程序片段(04):Test.c+劫持.c+p.c
内容概要:函数指针
///Test.c
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
void go()
{
printf("%s
", "老穆就要回山东!
");
}
void show()
{
MessageBoxW(0, L"欢送老穆!", L"回山东!", 0);
}
//01.普通指针和函数指针:
// 普通指针:只能操作数据区
// 函数指针:可以操作代码区,再通过操作代码区的方式实现间接操作数据区
// 注:函数指针的类型就是除开变量名称的那部分,只有同类型的函数指针才能进行修改赋值
//02.函数声明和函数实体:
// 函数声明:函数指针
// 函数实体:函数执行体代码区
// 注:严格区分数据区和代码区
// 函数指针变量和函数实体变量的区别!
// 1.函数指针变量当中存储的是函数实体变量的地址
// 2.通过不断的修改函数指针变量所存储的函数实体变量的地址
// 可以让同一个函数指针执行不同的函数函数实体
//03.对于函数指针而言的特殊性:
// 1.函数名的本质:就是函数指针-->然后就可以通过函数指针与函数实体的关系,间接的通过函数指针找到函数实体
// 函数指针和函数实体之间的关联切忌注意(只要知道了函数指针,就相当于知道了函数实体,只不过中间的查找过程
// 并没有像指针变量和普通变量之间的数值关系直接体现,而是隐含着进行体现的)-->函数声明地址-->函数定义地址
// 2.对函数名使用取地址符和直接获取函数名所对应的数值是一样的效果
// 注:
// 指针变量-->普通变量的地址:直接联系-->普通变量
// 函数指针-->函数声明的地址:中间忽略-->函数实体(后面实现的是自动链接特点)
// 相当于通过函数指针可以直接找到函数声明的位置,
// 但是,通过函数声明的位置如何找到函数实体的位置,
// 我们不需要关系,系统会自动链接到函数实体
int main01(void)
{
//go();
printf("%p
", go);
//printf("%p
", &go);
//void(*funP)() = go;
//funP();//可以存储不同函数的地址,执行不同的代码块儿
//funP = show;
//funP();
system("pause");
}
程序片段(05):run.c+劫持.c
内容概要:代码区劫持
///run.c
#include <stdio.h>
#include <stdlib.h>
void add() {}
void go() {}
//01.函数指针常量不允许修改的原因:
// 1.常量:本身就不应当被修改(类似于字符串的常量,字符串常量池当中的内容不允许直接被修改,因此代码区当中的内容也不允许被修改)
// 类似于字符串(因为同样属于代码区的内容,都具备相同的不可修改特点)
// 2.代码区:代码区的内容不允许被修改(权限不够),但是通过微软亚洲研究院的劫持工具Detours可以实现
// 注:劫持工具Detours详解
// 1.能够通过Detours工具找到任何运行程序的代码区
// 2.能够突破代码区的不可修改权限
// 使用特点:
// 1.可以进行跨平台编译(Windows,Linux,Android,iOS)跨平台劫持
// 2.不会修改原始程序的内容,只会修改程序加载进内存当中的代码区内容
int main01(void)
{
//add = go;//代码区,不允许
system("pause");
}
///劫持.c
#include <stdio.h>
#include <stdlib.h>
#include<Windows.h>
void go()
{
printf("%s
", "老穆就要回山东!");
}
void show()
{
MessageBoxW(0, L"欢送老穆!", L"回山东!", 0);
}
//01.函数指针与函数指针变量的区别:
// 直接书写函数名称:
// 叫做函数指针:是一个函数指针常量,因此直接获取函数名的值和获取函数名的地址是一样的(同样是函数指针常量值)
// 定义函数指针变量:
// 叫做函数指针变量:是一个函数指针变量,直接的函数指针变量的值和对函数指着变量取地址所获得的值不相同
// 注:函数指针常量和函数指针变量:
// 函数指针常量没有取地址与非取地址的区别
// 函数指针变量具有取地址与非取地址的区别
int main02(void)
{
void(*funP)() = go;
printf("go = %p, show = %p, funP = %p, &funp = %p
", go, show, funP, &funP);
while (1)
{
funP();
Sleep(1000);//防止进程卡死
}
system("pause");
}
///p.c
//特别注意:
//01.函数指针常量和函数指针变量之间的区别
// 1.函数名:函数指针常量,没有取地址与非取地址的区别
// 2.函数指针变量:具有取地址与非取地址之间的区别
//02.如何修改函数的执行行为?
// 1.必须借助函数指针变量,函数指针常量是不行的
// 2.改变行为有两种方式:
// 直接改变:同一个进程
// 一级函数指针变量
// 间接修改:不同的进程
// 二级函数指针变量
_declspec(dllexport) void changeFun()
{
void(**funFunP)() = (void (**)())0x0018F84C;//二级函数指针变量
*funFunP = (void (*)())0x002912A8;//一级函数指针变量
}
///劫持.c
#include <stdio.h>
#include <stdlib.h>
//01.劫持头文件说明:
// 1.必需的头文件:
// #include <Windows.h>
// #include "detours.h"
// 2.严格的头文件包含(方式|顺序)
// detours.h依赖于Windows.h
// 注:编译时期所使用的目录和链接时期所使用的目录的配置选项不同
// 编译时期所需要的自定义目录:
// 配置属性-->VC++目录:包含目录+库目录
// 连接时期所需要的自定义目录:
// 配置属性-->连接器-->输入:静态库lib的目录指向
#include <Windows.h>
#include "detours.h"
//02.静态库链接的两种方式:
// 1.项目配置:
// 指定项目-->配置属性-->链接器-->输入-->附加项
// 2.编译注释:(预编译指令的方式)
// #pragma comment(lib, "detours.lib")//包含库文件
#pragma comment(lib, "detours.lib")//静态库链接
//03.system();函数声明形式说明:
// 格式:
// _DCRTIMP int __cdecl system(_In_opt_z_ char const* _Command);
// 要点:
// _DCRTIMP(函数调用约定)
// __cdecl:标识C语言函数的默认调用方式(参数必须完全匹配)
// __cdecl是C Declaration的缩写(declaration,声明)表示C语言默认的函数调用方法:
// 所有参数从右到左依次入栈,这些参数由调用者清除,称为手动清栈.
// 被调用函数不会要求调用者传递多少参数,调用者传递过多或者过少的参数,甚至完全不同的参数都不会产生编译阶段的错误.
//04.系统函数指针变量的声明方式:
// 1.意义:给函数指针变量赋予函数指针常量的值
// 2.要想动态修改某个指定函数指针变量的执行行为所必需的首要前提:
// (1).必需有一级函数指针变量
// (2).必需能够直接或间接的修改一级函数指针变量的函数实体指向
// (3).必需前后进行一级函数指针的调用
// 3.通过劫持函数可以实现的行为:
// 在原有功能的基础之上,劫持原有功能的某些有用信息
// 4.劫持函数的定义特点:
// (1).劫持函数属于是函数指针常量(代码区的代码不变,行为的固定)
// (2).劫持函数的时候如果存在宽字符的函数,就只能劫持宽字符的函数,因为Detours为了提高兼容性
// (3).劫持函数可以实现黑白名单的放行特点
int(*sysFunOldP)(char const* _Command) = system;//存放system函数声明的地址
int sysFunNewP(char const* _Command)//劫持函数的编写
{
printf("您执行的是%s
", _Command);//打印:记录,日志
//sysFunOldP(_Command);
//char * exist = strstr(_Command, "360");//检索360关键字
//if (NULL == exist)
//{//黑白名单测试
// printf("良名! 速速放行!
");
// sysFunOldP(_Command);
//}
//else
//{
// printf("哼! 周鸿祎这个老刁民! 老夫就是不放行!
");
//}
return 1;
}
void executeHook()
{
DetourRestoreAfterWith();//恢复之前状态(未劫持的状态),防止反复进行劫持-->防止一条指令被重复劫持
DetourTransactionBegin();//劫持事务开始
DetourUpdateThread(GetCurrentThread);//更新当前线程状态,让线程准备好执行劫持动作
DetourAttach((void **)&sysFunOldP, sysFunNewP);//发出劫持攻击动作(相当于修改一级函数指针的执行行为)
DetourTransactionCommit();//劫持事务提交
}
//01.微软亚洲研究院(劫持|反劫持)工具详解:
// 1.使用原因:
// (1).可以根据任何程序的函数名称找到相应的代码区
// (2).可以突破加载进内存的程序代码区不可修改权限
// ***可以劫持所有函数(包括系统级别的函数),该工具(Detour)经常用于信息安全方面
// 2.使用特点:
// (1).可以实现跨平台(Windows|Linux|Android|iOS)的劫持与反劫持
// (2).不能修改程序原始代码,修改的只是程序被加载进内存代码区的临时代码
// (3).可以实现所有函数的(劫持|反劫持),是一种具备比sys权限更高的底层权限
// 因此,可以通过该权限跨国sys权限进行操作(例如跨过360权限)
// (4).可以衍生的劫持类型:实质(通过函数指针常量劫持函数实体常量)
// 文件劫持,日志劫持,网络劫持...-->号称最高权限,超越系统(sys),超越驱动(driver)-->突破运行时程序的代码区不可修改权限
// (5).劫持技术起源于2002年,俄罗斯.圣彼得堡;但是Detours工具是由微软亚洲研究院编写的
// 3.使用方式:
// (1).进行程序跨平台编译
// Windows:使用nmake指令(编译之前必须配置环境变量,建议通过VS命令行工具进行编译)
// (2).导入头文件(C语言奇葩)和静态库文件
// (3).(劫持|反劫持)核心函数编写
// (4).Detours编译之后的文件夹说明:
// 注意事项:劫持必需在调试环境下才能顺利进行,靶子程序和劫持程序都必须在调试环境下进行方可
// (5).劫持技术只能用于Release版本不能用于Debug版本,因为防止与Debug模式下的其它劫持现象冲突
// 而Release版本下的劫持默认并没有开启
// (6).严格注意Detour的版本限制:
// Express:只能用于32位操作系统及应用程序
// Pro:既能用于32位操作系统及应用程序也能用于64位操作系统及应用程序
//02.劫持常用分类:
// 1.按照待劫持程序分类:
// 劫持本程序
// 劫持其它程序
// 劫持系统程序
// 2.按照劫持对象进行分类:
// 劫持文件
// 劫持进程
// 劫持网络
//03.注意劫持状态的保留情况
// DLL注入的时候需要劫持状态保留
//04.关于函数名的几种操作方式的相同点:
// &(funName)=*(funName)=funName
// 操作系统所做的简化方式:
// 早期函数的调用方式*(funName)();早期C语言的函数调用方式
// 后期进行了简化,以至于&fun<==>*fun<==>fun
// 因为函数指针常量的不同调用其意义实质都一样,所以做了简化
int main02(void)
{
system("notepad");
executeHook();
system("notepad");
system("notepad");
system("mspaint");
system("tasklist");
system("pause");
}
程序片段(06):劫持.c
内容概要:劫持其他人
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include "detours.h"
#pragma comment(lib, "detours.lib")
int(*sysFunOldP)(char const* _Command) = system;
int sysFunNewP(char const* _Command)
{
MessageBoxW(0, L"请给老穆交保护费!", L"否则不准执行! 我是流氓我怕谁?", 0);
return 1;
}
void executeHook()
{
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach((void **)&sysFunOldP, sysFunNewP);
DetourTransactionCommit();
}
_declspec(dllexport) void hook()
{
executeHook();
getchar();//保留劫持状态
}
程序片段(07):CreateProcess.c+爆了周鸿祎.c
内容概要:360Safe劫持
///CreateProcess.c
#include <Windows.h>
//01.Windows自带函数特点解析:
// 1.WINBASEAPI:
// Windows基础API,其它创建进程的方式都依赖于该函数的实现
// 2.CreateProcessW:
// 采用Unicode编码方式实现的创建进程函数,因此通用劫持函数就是它
// 3.创建应用程序进程的两种交互方式:
// 图形化界面+命令行界面
//WINBASEAPI-------------------------------------------------->Windows最基本的应用程序接口
//BOOL---------------------------------------------------------->创建进程成功与否
//WINAPI-------------------------------------------------------->标识该接口属于WindowsAPI
//CreateProcessW(---------------------------------------------->兼容性最强的进程创建函数
// _In_opt_ LPCWSTR lpApplicationName,--------------------->图形化方式创建的应用程序进程
// _Inout_opt_ LPWSTR lpCommandLine,---------------------->命令行方式创建的应用程序进程
// _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,---->应用程序进程的安全属性集
// _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,----->应用程序进程主线程的安全属性集
// _In_ BOOL bInheritHandles,---------------------------------->继承附加参数
// _In_ DWORD dwCreationFlags,------------------------------->创建标识参数
// _In_opt_ LPVOID lpEnvironment,----------------------------->环境变量的指针
// _In_opt_ LPCWSTR lpCurrentDirectory,----------------------->当前进程的所属路径
// _In_ LPSTARTUPINFOW lpStartupInfo,----------------------->进程启动的附加信息
// _Out_ LPPROCESS_INFORMATION lpProcessInformation--->进程信息标识符
// );
int main01(void)
{
STARTUPINFO si = { sizeof(si) };//进程启动信息-->结构体成员初始化
PROCESS_INFORMATION pi;//进程信息
si.wShowWindow = 1;//显示窗口
si.dwFlags = STARTF_USESHOWWINDOW;//使用显示窗口
wchar_t str[100] = L"notepad";
CreateProcess(NULL, str, NULL, NULL, 0, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
system("pause");
}
///爆了周鸿祎.c
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include "detours.h"
#pragma comment(lib, "detours.lib")
BOOL(*cpwFunOldP)(//一级函数指针变量
_In_opt_ LPCWSTR lpApplicationName,
_Inout_opt_ LPWSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCWSTR lpCurrentDirectory,
_In_ LPSTARTUPINFOW lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
) = CreateProcessW;//采用宽字符接收待创建进程的名称-->通用创建进程函数(Unicode编码)-->通用一级函数指针变量
BOOL cpwFunNewP(//函数指针常量
_In_opt_ LPCWSTR lpApplicationName,
_Inout_opt_ LPWSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCWSTR lpCurrentDirectory,
_In_ LPSTARTUPINFOW lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation)
{//既然采用Unicode编码处理字符串,那么该函数的所有地方都必须采用宽字符解决问题,整个项目都必须采用宽字符进行解决
wchar_t * result1;
wchar_t * result2;
result1 = wcsstr(lpApplicationName, L"360");
result2 = wcsstr(lpCommandLine, L"360");
if (NULL != result1 && NULL != result2)
{
MessageBoxW(0, L"周鸿祎,不交保护费,不允许通过!", L"否则周瑞富要爆你的菊花!", 0);
return 0;//执行失败
}
MessageBoxW(0, L"良名大大的,不要学流氓!", "周瑞富为了感谢你,把周鸿祎的泷泽萝拉让给你!", 0);
cpwFunOldP(
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation
);
return 1;
}
void hook()
{
DetourRestoreAfterWith();//重置劫持状态,防止重复劫持
DetourTransactionBegin();//劫持事务开始
DetourUpdateThread(GetCurrentThread());//刷新当前线程,为劫持状态做准备
DetourAttach((void **)&cpwFunOldP, cpwFunNewP);//劫持攻击
DetourTransactionCommit();//劫持事务提交
}
void unHook()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach((void **)&cpwFunOldP, cpwFunNewP);//反劫持状态
DetourTransactionCommit();
}
_declspec(dllexport) void executeHook()
{
hook();
int i = 0;
while (i)
{
Sleep(1000);
++i;
if (i > 60)
unHook();
}
system("pause");//保留劫持持续状态
}
程序片段(08):01.数组递归.c+02.递归.c
内容概要:小小递归
///01.数组递归.c
#include <stdio.h>
#include <stdlib.h>
//01.如何判定一个数组递变关系?
// 1.递变关系:递增或者递减
// 2.解决方案:只要存在一种不满足的情况,就被淘汰掉!
int main01(void)
{
int intArr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
//递增关系:
// 针对于任何两个数组元素,都必须满足
// intArr[n] < intArr[n + 1];
int order = 1;//标识符:用于标识多数情况
for (int i = 0; i < 10 - 1; ++i)
{
if (intArr[i] > intArr[i + 1])
{//用于描述存在情况,用于明显否定
order = 0;
break;//效率问题
}
}
if (order)
printf("递增!
");
else
printf("非递增!
");
system("pause");
}
//01.递归关系的描述特点:
// 1.算数运算符描述
// 2.逻辑运算符描述:描述整个递推关系的同时成立性质
// 多个情况同时成立采用逻辑与运算符进行描述;
// 如果存在一种情况不符合要求,就用逻辑与进行描述
// 3.关系表达式的含义:
// a[EN-1]>a[EN-2]:
// (1).EN:表示数组元素的总个数!
// (2).当前关系成立情况:最后一个元素>倒数第二个元素
// (3).递推关系成立情况:isOrder(intArr, i - 1)
// (4).表示所有关系的成立情况,就用逻辑与运算符进行并运算
// 其中只要有一个不成立,那么总体返回结果就是不成立情况
// ***递推关系的描述特点
int isOrder(int intArr[10], int EN)
{
if (1 == EN)
return 1;
else if (2 == EN)
return intArr[0] < intArr[1];
if (intArr[EN - 2] > intArr[EN - 1])
return 0;
else//这是一种递归加速的方式,减少不必要的递归次数!
return isOrder(intArr, EN - 1);
//return intArr[EN - 2] < intArr[EN - 1] && isOrder(intArr, EN - 1);
}
int main02(void)
{
int intArr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int order = isOrder(intArr, 10);
if (order)
printf("递增!
");
else
printf("非递增!
");
system("pause");
}
///02.递归.c
#include <stdio.h>
#include <stdlib.h>
//01.递推关系的顺序描述:
// f(100)=100+f(99);
// f(99)=99 +f(98);
// f(98)=98 +f(97);
// f(n)=n +f(n-1);
// f(1)=1---------->
// 任何一项都只会依赖于其下一项,因此只需要知道任何一项,就能够知道所有项
// 前项递推+后向递推+双向递推(只需要任意一个已知项,就可以完成(所有项的自动推导)
int nItemSelf(int nItem)
{//正向思维:从后往前推导,描述关系(已知条件在前)
if (1 == nItem)
return 1;//已知首项是多少?-->从后往前推
return nItem + nItemSelf(nItem - 1);
}
//02.递推关系的逆序描述;
// sub(0) 5050 -->5050 - (0)
// sub(1) 5049 -->5050 - (0+1)
// sub(2) 5047 -->5050 - (0+1+2)
// sub(3) 5044 -->5050 - (0+1+2+3)
// ...
// sub(n)= sub(0) - (0 + 1 + 2 + 3 + ... + n)
//------------------------------------------------
// sub(0) 5050
// sub(1) 5049
// sub(99) 100
// sub(100) 0
// sub(100)+100=sub(99);
// sub(100)=sub(99)-100;
// sub(100)+(1+2+3+...+n-2+n-1+100) = sub(0);
// sub(100)=sub(0) - (1+2+3+...+n-2+n-1+100);
// sub(99)+(1+2+3+...+n-2+n-1+99)=sub(0);
// sub(99)=sub(0)+(1+2+3+...+n-2+n-1+99);
// sub(n)=sub(n-1)-n;//关系式推导(补充上少减去的那个部分)
int nItemSubResult(int result, int nItem)
{//逆向思维:从前往后进行推导,描述关系(已知条件在后)
if (0 == nItem)
return result;//已知总和是多少?-->从前往后推
return nItemSubResult(result, nItem - 1) - nItem;
}
int main03(void)
{
printf("%d
", nItemSelf(99));//4950
printf("%d
", nItemSubResult(5050, 99));//100
system("pause");
}
程序片段(09):go.c
内容概要:CreateThread
#include <Windows.h>
//01.标准线程任务函数定义格式:
// DWORD:typedef unsigned long DWORD;
// unsigned long(类型)
// WINAPI:#define WINAPI __stdcall
// _stdcall(C语音函数标准调用方式)
// LPVOID:typedef void far *LPVOID;
// LPVOID(空类型指针)
DWORD WINAPI threadTask(LPVOID lp)
{
MessageBoxW(0, L"Hello!", L"China!", 0);
}
//02.单线程和多线程:
// 1.使用多线程既可以实现多线程并发访问,也可以实现单线程同步执行
// 2.在顺序,循环,分支的情况之下只能满足同步需求,绝对不能满足异步
// 需求,异步需求必须满足多线程要求
// 3.C++语言的所有函数库都依赖于C语言的标准核心函数实现
// 什么临界区,信号量,互斥量,原子量,都是依赖于C语言线程核心函数实现
int main01(void)
{
HANDLE hthread;//线程操作句柄
DWORD threadid;//线程标识ID
for (int i = 0; i < 5; ++i)
{
hthread = CreateThread(
NULL,//线程安全属性集
NULL,//线程堆栈尺寸
threadTask,//线程任务函数(函数指针(常量/变量))
NULL,//线程任务函数所需参数
0,//立即执行
&threadid//保存线程id
);
//异步创建线程的方式
}
for (int i = 0; i < 5; ++i)
{
hthread = CreateThread(
NULL,//线程任务属性集
NULL,//线程函数堆栈尺寸
threadTask,//线程任务函数(函数指针(常量/变量))
NULL,//线程任务函数所需实参
0,//立即执行
&threadid//线程标识ID
);
WaitForSingleObject(hthread, INFINITE);//为了单实例进行等待(INFINITE:无限等待)
CloseHandle(hthread);//关闭线程句柄(释放线程运行所占用的内存单元)
}
system("pause");
}