u1timate
发布于 2025-03-15 / 11 阅读
0
0

1、恶意代码基础

超过用户使用预期的代码叫做恶意代码

恶意代码在windows中常见的运行方式

  • 在硬盘中存在

  • 不在硬盘中存在(比如直接在内存中)

0x01、C++

首先安装visual studio

测试是否正常使用

#include<iostream>  //导入库

using namespace std;  //命名空间,原来处理标准使用词

int main() {
	cout << "Hello world";
	return 0;
}

C++七种数据类型

类型

关键字

布尔型

bool

字符型

char

整型

int

浮点型

float

双浮点型

double

无类型

void

宽字符型

wchar_t

每个字符的占位如下 sizeof(size_t)

类型

范围

char

1个字节

-128~127 或者0~255

unsigned char

1个字节

0到255

signed char

1个字节

-128~127

int

4个字节

-2147483648~2147483647

unsigned int

4

0~4294967295

signed int

4

-2147483648~2147483647

short int

2

-32768~32767

unsigned short int

2

0~65535

signed short int

2

-32768~32767

long int

8

-9223372.036,854.775,808 到9,223 372,036,854 775807

signed long int

8

-9223372.036,854.775,808 到9,223 372,036,854 775807

unsigned long int

8

0到 18,446,744,073,709 551,615

float

4

精度型占4个字节(32位)内存空间,+/-3.4e +/- 38(~7 个数字)

double

8

双精度型占8个字节(64位)内存空间,+/-1.7e +/- 308(~15 个数字)

long long

8

long double

16

128位内容空间,可以提供18~19位有效数字

wchar_t

2或者4个字节

1个宽字符

可以使用typedef为已有的类型取一个新的名字

// typedef type newname;
typedef int z_int;

类型转换(静态)

int a= 1;
static_case<float>(a);

类型转换(强制)

int a=1;
char chara = (char)a;

定义常量

#define identifier value
const char a ='q';

修饰符

  • signed : 表示变量可以存储负数,对于整型变量来说,signed可以省略

  • unsigned:表示变量不能存储负数,对于整型变量来说,可以将变量范围扩大一倍

  • short:表示变量范围比int更小, short int可以缩写short

  • long:表示变量的范围比int更大, long int 可以缩写为long。

位运算符

运算符

描述

&

按位与操作,规则如下

0&0=0;

0&1=0;

1&0=0;

1&1-1;

|

按位或运算符

^

按位异或运算

相同为0,不同为1

0^0=0;

0^1=1;

1^0=1;

1^1=0;

多变量的集合

数组

double balance[5] = { 1000.0, 2.0,3.4, 7.0, 50.0 };
double salary = balance[3]; 
char name[] = "cutecuteye"; //多个字符组成的字符串可以写成字符数组

字符串

strcpy(s1,s2);
strcat(s1,s2);
string str1="hello";
string str2="world";
string str = str1+str2;
strlen(str); //返回字符串的长度
strcmp(s1,s2); //s1和s2相同返回0;s1<s2返回小于0;

结构体

结构体中建好了一个类型就必须要定义一个对象,外面的结构体就没有这个要求。

struct Books
{
    char title[50];
    char author[50];
    int subject[100];
    int book id;
    struct PP{
        int P1=2;
    }PP;
}
//定义
/*
struct是保留字
struct 结构体类型的名字
{
    结构体中的变量类型 结构体中的变量名称;
}
*/
//使用
Books Book1;
Book1.book_id=12345;

函数

return_type function name(parameter list)
//返回值类型           函数名称  参数类型和参数名
{
    body of the function//函数代码
}

函数的调用一定要写在函数定义的下面,不然会报错也可以使用两数声明的方式,如下

#include<iostream>
using namespace std;

int test(int a, int b);

int main(){
    int d = test(1,2); 
    return 0;
}

int test(int a, int b){
    int c;
    return a+b;
}

指针在安全中的两种常用方式

  • 目标数据我们没有权限,但是指针的位置有权限

  • 目标数据我们找不到具体的位置,但是指针的位置是固定的。

windowsAPI

该API是windows操作系统与应用程序的接口

https:/learn.microsoft.com/zh-cn/docs/

  • 使用api实现一个利用注册表开机启动的小程序

#include <windows.h>
#include <iostream>
#include <string>

// 注册表路径,用于设置开机启动
const std::wstring REGISTRY_RUN_PATH = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";

// 添加程序到注册表开启开机启动
bool AddToStartup(const std::wstring& appName, const std::wstring& exePath) {
    HKEY hKey;
    // 打开/创建 注册表键
    if (RegOpenKeyEx(HKEY_CURRENT_USER, REGISTRY_RUN_PATH.c_str(), 0, KEY_WRITE, &hKey) != ERROR_SUCCESS) {
        std::wcerr << L"无法打开注册表键\n";
        return false;
    }

    // 写入注册表项
    if (RegSetValueEx(hKey, appName.c_str(), 0, REG_SZ, 
                      reinterpret_cast<const BYTE*>(exePath.c_str()), 
                      static_cast<DWORD>((exePath.size() + 1) * sizeof(wchar_t))) != ERROR_SUCCESS) {
        std::wcerr << L"无法设置注册表值\n"; 
        RegCloseKey(hKey);
        return false;
    }

    RegCloseKey(hKey);
    return true;
}

// 检查是否存在启动项
bool CheckStartup(const std::wstring& appName, std::wstring& exePathOut) {
    HKEY hKey;
    wchar_t buffer[MAX_PATH];
    DWORD bufferSize = sizeof(buffer);

    // 打开注册表键
    if (RegOpenKeyEx(HKEY_CURRENT_USER, REGISTRY_RUN_PATH.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
        std::wcerr << L"无法打开注册表键\n";
        return false;
    }

    // 查询指定的注册表值
    if (RegQueryValueEx(hKey, appName.c_str(), 0, nullptr, 
                        reinterpret_cast<LPBYTE>(buffer), &bufferSize) == ERROR_SUCCESS) {
        exePathOut = buffer; // 获取到的路径
        RegCloseKey(hKey);
        return true;
    }

    RegCloseKey(hKey);
    return false;
}

// 从注册表中移除开机启动项
bool RemoveFromStartup(const std::wstring& appName) {
    HKEY hKey;

    // 打开注册表键
    if (RegOpenKeyEx(HKEY_CURRENT_USER, REGISTRY_RUN_PATH.c_str(), 0, KEY_WRITE, &hKey) != ERROR_SUCCESS) {
        std::wcerr << L"无法打开注册表键\n";
        return false;
    }

    // 删除注册表值
    if (RegDeleteValue(hKey, appName.c_str()) != ERROR_SUCCESS) {
        std::wcerr << L"无法删除注册表值\n";
        RegCloseKey(hKey);
        return false;
    }

    RegCloseKey(hKey);
    return true;
}

int main() {
    std::wstring appName = L"MyApp"; // 启动项名称
    wchar_t exePath[MAX_PATH];
    
    // 获取当前程序路径
    if (GetModuleFileName(nullptr, exePath, MAX_PATH) == 0) {
        std::wcerr << L"无法获取程序路径\n";
        return 1;
    }

    std::wcout << L"当前程序路径: " << exePath << std::endl;

    // 检查是否已经在启动项中
    std::wstring existingPath;
    if (CheckStartup(appName, existingPath)) {
        std::wcout << L"启动项已存在: " << existingPath << std::endl;
    } else {
        std::wcout << L"启动项不存在,添加中...\n";
        if (AddToStartup(appName, exePath)) {
            std::wcout << L"成功添加开机启动。\n";
        } else {
            std::wcerr << L"添加开机启动失败。\n";
            return 1;
        }
    }

    // 移除启动项(可注释掉此段代码进行测试)
    if (RemoveFromStartup(appName)) {
        std::wcout << L"已成功移除启动项。\n";
    } else {
        std::wcerr << L"移除启动项失败。\n";
    }

    return 0;
}

0x02 DLL

DllMain 函数

DllMain 是 DLL 的入口点,由操作系统调用,它主要用于响应 DLL 的加载和卸载事件。系统会自动调用,无需手动调用或暴露给外部用户。不能用来导出函数给外部调用,它仅供操作系统调用,并用于管理 DLL 的生命周期。

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        // 进程加载了 DLL
        // 适合执行一次性的初始化代码
        break;

    case DLL_THREAD_ATTACH:
        // 线程加载了 DLL
        // 适合执行线程相关的初始化代码
        break;

    case DLL_THREAD_DETACH:
        // 线程正常退出
        // 用于释放线程相关的资源
        break;

    case DLL_PROCESS_DETACH:
        // 进程卸载了 DLL
        // 释放全局资源、关闭句柄等清理工作
        break;
    }
    return TRUE; // 返回 TRUE 表示初始化成功
}
  • DLL_PROCESS_ATTACH:进程加载了 DLL。 发生在进程启动时(比如调用 LoadLibrary LoadLibraryEx 加载 DLL 时(动态链接)。此状态只影响进程级别,因此通常执行一次初始化。

  • DLL_THREAD_ATTACH:进程中的一个线程加载了 DLL。当进程中的线程被创建时,并且该进程已经加载了 DLL。通常用于进行线程级别的初始化,例如为新线程分配线程局部存储(TLS)。

  • DLL_THREAD_DETACH:进程中的一个线程正常退出。当线程退出时,卸载 DLL 时会调用此分支。用于清理线程相关资源,例如释放线程局部存储。如果线程是通过 TerminateThread 终止的,这个状态不会被触发。

  • DLL_PROCESS_DETACH:进程卸载 DLL。发生在进程结束时(如果 DLL 是静态链接的)或者调用 FreeLibrary 或卸载 DLL 时(动态链接)。

完成编译成dll,类似于如下代码调用即可

#include<windows.h>

void main(){
	LoadLibraryA("dll1.dll")
}

直接导出函数

通过 __declspec(dllexport) 显式导出一些函数,这些函数可以被外部程序通过 LoadLibrary GetProcAddress 动态加载并调用。提供真正的业务功能,例如计算、工具函数、逻辑操作等。

提供 API 给其他程序使用。出函数仅用于提供功能,并不直接处理 DLL 的生命周期。

#include <windows.h>
#include <iostream>

// 导出函数声明
extern "C" __declspec(dllexport) void HelloWorld()
{
    MessageBox(NULL, TEXT("Hello, World!"), TEXT("Message from DLL"), MB_OK);
}

调用该dll

#include <windows.h>
#include <iostream>

// 方法类型定义
typedef void (*HelloWorldFunc)();

int main()
{
    // 加载 DLL
    HINSTANCE hDLL = LoadLibrary(TEXT("SimpleDLL.dll"));
    if (hDLL == NULL)
    {
        std::cerr << "Failed to load DLL\n";
        return -1;
    }

    // 获取导出函数地址
    HelloWorldFunc helloWorld = (HelloWorldFunc)GetProcAddress(hDLL, "HelloWorld");
    if (helloWorld == NULL)
    {
        std::cerr << "Failed to find function in DLL\n";
        FreeLibrary(hDLL);
        return -1;
    }

    // 调用导出函数
    helloWorld();

    // 释放 DLL
    FreeLibrary(hDLL);
    return 0;
}


评论