20160204.CCPP體系詳解(0014天)

尹成發表於2016-02-16

程式片段(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("------------------------------------ \n");
    for (int i = 0; i < N; ++i)
    {
        for (int j = 0; j < N; ++j)
        {
            printf("%2d", maze[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}
///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("能夠形成迷宮通路! \n");
        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("不可以走出! \n");
    else                                                                                                                 
    {
        printf("可以走出! \n");
        showMaze(AIPath);
        AIMazeMove();
    }

    system("pause");
}

程式片段(02):main.c
內容概要:GccArray

#include <stdio.h>
#include <stdlib.h>

int main()
{
    printf("Hello world!\n");

    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 \n", &num);//取地址運算子&-->獲取地址
    *(&num) = 3;//指標運算子*-->宣告指標+根據地址獲取內容
    //&num = 0x123;//取地址運算子&num所執行的操作位於暫存器,C語言無法直接給暫存器進行賦值操作
    printf("%d \n", num);

    system("pause");
}

//02.指標變數:
//  1.區分直接賦值與間接賦值:
//      直接賦值:直接操作變數本身,也就是記憶體實體(資料實體)本身
//      間接賦值:通過指標變數(儲存普通變數所屬地址的變數)間接操作記憶體實體(資料實體)本身
//  2.使用指標變數的意義:
//      間接的操作記憶體實體(資料實體)本身
int main02(void)
{
    int num = 10;
    //num = 4;//直接賦值
    int * numP = &num;//pNum是一個指標變數(地址變數)
    printf("%p \n", numP);//列印指標變數所儲存的具備地址含義的數值,也就是普通變數的地址-->一級指標含義
    printf("%p \n", &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 \n", "老穆就要回山東! \n");
}

void show()
{
    MessageBoxW(0, L"歡送老穆!", L"回山東!", 0);
}

//01.普通指標和函式指標:
//  普通指標:只能運算元據區
//  函式指標:可以操作程式碼區,再通過操作程式碼區的方式實現間接運算元據區
//  注:函式指標的型別就是除開變數名稱的那部分,只有同型別的函式指標才能進行修改賦值
//02.函式宣告和函式實體:
//  函式宣告:函式指標
//  函式實體:函式執行體程式碼區
//  注:嚴格區分資料區和程式碼區
//      函式指標變數和函式實體變數的區別!
//          1.函式指標變數當中儲存的是函式實體變數的地址
//          2.通過不斷的修改函式指標變數所儲存的函式實體變數的地址
//              可以讓同一個函式指標執行不同的函式函式實體
//03.對於函式指標而言的特殊性:
//  1.函式名的本質:就是函式指標-->然後就可以通過函式指標與函式實體的關係,間接的通過函式指標找到函式實體
//      函式指標和函式實體之間的關聯切忌注意(只要知道了函式指標,就相當於知道了函式實體,只不過中間的查詢過程
//      並沒有像指標變數和普通變數之間的數值關係直接體現,而是隱含著進行體現的)-->函式宣告地址-->函式定義地址
//  2.對函式名使用取地址符和直接獲取函式名所對應的數值是一樣的效果
//  注:
//      指標變數-->普通變數的地址:直接聯絡-->普通變數
//      函式指標-->函式宣告的地址:中間忽略-->函式實體(後面實現的是自動連結特點)
//          相當於通過函式指標可以直接找到函式宣告的位置,
//          但是,通過函式宣告的位置如何找到函式實體的位置,
//          我們不需要關係,系統會自動連結到函式實體
int main01(void)
{
    //go();

    printf("%p \n", go);
    //printf("%p \n", &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 \n", "老穆就要回山東!");
}

void show()
{
    MessageBoxW(0, L"歡送老穆!", L"回山東!", 0);
}

//01.函式指標與函式指標變數的區別:
//  直接書寫函式名稱:
//      叫做函式指標:是一個函式指標常量,因此直接獲取函式名的值和獲取函式名的地址是一樣的(同樣是函式指標常量值)
//  定義函式指標變數:
//      叫做函式指標變數:是一個函式指標變數,直接的函式指標變數的值和對函式指著變數取地址所獲得的值不相同
//  注:函式指標常量和函式指標變數:
//      函式指標常量沒有取地址與非取地址的區別
//      函式指標變數具有取地址與非取地址的區別
int main02(void)
{
    void(*funP)() = go;
    printf("go = %p, show = %p, funP = %p, &funp = %p \n", 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 \n", _Command);//列印:記錄,日誌
    //sysFunOldP(_Command);

    //char * exist = strstr(_Command, "360");//檢索360關鍵字
    //if (NULL == exist)
    //{//黑白名單測試
    //  printf("良名! 速速放行! \n");
    //  sysFunOldP(_Command);
    //}
    //else
    //{
    //  printf("哼! 周鴻禕這個老刁民! 老夫就是不放行! \n");
    //}
    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("遞增! \n");
    else
        printf("非遞增! \n");

    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("遞增! \n");
    else
        printf("非遞增! \n");

    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 \n", nItemSelf(99));//4950
    printf("%d \n", 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");
}

相關文章