BOF编写-修改时间戳

打印 上一主题 下一主题

主题 916|帖子 916|积分 2748

模板配置

跟着网上的教程使用evilashz师傅的模板,下载模板解压至vs的模板目次:
  1. %UserProfile%\Documents\Visual Studio 2022\Templates\ProjectTemplates
复制代码

创建新项目选择刚刚新增的类型:Beacon Object File​。


环境适配

天生时报错,我使用的是2022版本的,模板有点老了他这里的是vs2019。

根据底下的提示从项目​ -> 重定目标解决方案​, 接着确定更新即可

但是一进来模板会报错没有引入库,  干脆就用最小测试代码:将 Source.cpp​重名为Source.c​并修改为如下:
  1. #include <stdio.h>
  2. #include <Windows.h>
  3. #include "beacon.h"
  4. void go(char* buff, int len) {
  5.         BeaconPrintf(CALLBACK_OUTPUT, "Hello BOF");
  6. }
复制代码

编译配置

在上方的天生中勾选BOF配置, 配置管理器的编译环境也一样的,就可以天生64位版本的。

但最好还是使用批天生同时天生32位和64位版本:天生​ -> 批天生​ 在BOF那两项勾选Win32​和x64​。

创建项目时没有勾选将解决方案和项目放在同一目次下​,那么天生的.obj​文件(编译未链接的目标文件)就在/bin/BOF​中。

测试如果用cs的话可以使用inline-execute E:\TARGET\timestamp.obj​。我这里执行成功但发现有乱码:


乱码问题

尝试了加上\n​换行来终止字符串刷新缓冲区但是不行,找到使用格式化输出宏的办法,将可变参数睁开。比如这里的INFO_FORMAT("Hello BOF");​会被睁开成BeaconPrintf(CALLBACK_OUTPUT, "
  • Hello BOF\n");​。
    1. #include <stdio.h>
    2. #include <Windows.h>
    3. #include "beacon.h"
    4. #define INFO_FORMAT(fmt, ...)    BeaconPrintf(CALLBACK_OUTPUT, "[*] " fmt "\n", ##__VA_ARGS__)
    5. void go(char* buff, int len) {
    6.     INFO_FORMAT("Hello BOF");
    7. }
    复制代码
    原先的内存中大概是这样:"Hello BOF" ​,但使用宏之后就是这样的:"
  • Hello BOF\n" ​,最后测试也没有乱码了。


    功能实现

    实现一个修改文件时间戳的功能, BOF不能直接调用Windows API, 而是通过cs提供的函数来交互。但我这里并不是为cs编写,所以要使用Windows API函数的话,起首需要举行声明:
    Windows API声明

    要修改文件时间戳, 就要用到SetFileTime​。它用于设置文件的创建时间、访问时间和修改时间。文档中原型如下:
    1. BOOL SetFileTime(
    2.   [in]           HANDLE         hFile,
    3.   [in, optional] const FILETIME *lpCreationTime,
    4.   [in, optional] const FILETIME *lpLastAccessTime,
    5.   [in, optional] const FILETIME *lpLastWriteTime
    6. );
    复制代码


    • hFile: 文件句柄,必须有FILE_WRITE_ATTRIBUTES访问权限
    • lpCreationTime: 文件的创建时间
    • lpLastAccessTime: 文件的最后访问时间
    • lpLastWriteTime: 文件的最后修改时间
    那么在bof的声明中要留意这个函数是属于哪个dll, 比如这里是kernel32.dll​的话那要定义和调用它时就写成KERNEL32$SetFileTime​,完整如下:
    1. DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetFileTime(HANDLE, const FILETIME*, const FILETIME*, const FILETIME*);
    复制代码
    cs使用这种前缀可以让BOF直接调用DLL中的原生函数, 就不需要再在导入表中声明了,这样也可以缩小BOF体积。类似的使用CreateFileA​来创建或打开文件时, 其原型如下:
    1. HANDLE CreateFileA(
    2.   [in]           LPCSTR                lpFileName,                           // 文件名
    3.   [in]           DWORD                 dwDesiredAccess,            // 访问模式
    4.   [in]           DWORD                 dwShareMode,                          // 共享模式
    5.   [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes,  // 安全描述符
    6.   [in]           DWORD                 dwCreationDisposition, // 创建方式
    7.   [in]           DWORD                 dwFlagsAndAttributes,  // 文件属性
    8.   [in, optional] HANDLE                hTemplateFile                  // 模板文件句柄
    9. );
    复制代码
    BOF中声明则如下:
    1. DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileA(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
    复制代码
    以及其他要用到的api可以这样声明:
    1. // 其他必要的API
    2. DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle(HANDLE); // 关闭一个内核对象(如文件)的句柄
    3. DECLSPEC_IMPORT VOID WINAPI KERNEL32$GetSystemTime(LPSYSTEMTIME); // 获取当前系统时间(UTC时间)
    4. DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SystemTimeToFileTime(LPSYSTEMTIME, LPFILETIME); // 将SYSTEMTIME结构转换为FILETIME结构。
    复制代码

    参数处理

    BOF的入口函数就是这里的go, inline-execute​执行BOF时先调用这个。此中先定义并初始化一个解析器来解析传入的参数,timestamp​这个至少也是要一个参数路径的,先从一个来:
    1. void go(char* buff, int len) {
    2.     datap parser;
    3.     char* filepath;
    4.     // 解析Beacon传入的参数
    5.     BeaconDataParse(&parser, buff, len);
    6.     filepath = BeaconDataExtract(&parser, NULL);
    7.     // 参数验证
    8.     if (!filepath) {
    9.         BeaconPrintf(CALLBACK_ERROR, "[-] please provide file path");
    10.         return;
    11.     }
    12. }
    复制代码
    那解析多个参数呢, 一样的:
    1. BeaconDataParse(&parser, buff, len);
    2. sourceFile = BeaconDataExtract(&parser, NULL);
    3. targetFile = BeaconDataExtract(&parser, NULL);
    4. if (!sourceFile || !targetFile) {
    5.         BeaconPrintf(CALLBACK_ERROR, "[!] Error: Two file paths required\n");
    6.     BeaconPrintf(CALLBACK_ERROR, "[-] Usage: inline-execute timestamp.o "source_file" "target_file"\n");
    7.     return;
    8. }
    9. BeaconPrintf(CALLBACK_OUTPUT, "[-] Source: %s\n", sourceFile);
    10. BeaconPrintf(CALLBACK_OUTPUT, "[-] Target: %s\n", targetFile);
    复制代码

    时间处理

    接着继续,获取体系时间然后修改成我们希望的时间,比如2020年1月1日 00:00:00​。然后把他转换为文件时间格式:
    1. SYSTEMTIME st;
    2. FILETIME ft;
    3. KERNEL32$GetSystemTime(&st);
    4. st.wYear = 2020;
    5. st.wMonth = 1;
    6. st.wDay = 1;
    7. st.wHour = 0;
    8. st.wMinute = 0;
    9. st.wSecond = 0;
    10. KERNEL32$SystemTimeToFileTime(&st, &ft);
    复制代码

    文件操作

    准备好了要修改的时间后就尝试打开文件获取句柄:
    1. HANDLE hFile = KERNEL32$CreateFileA(
    2.     filepath,                                                 // 文件路径
    3.     FILE_WRITE_ATTRIBUTES,                                   // 只需要写属性权限
    4.     FILE_SHARE_READ | FILE_SHARE_WRITE,                 // 允许其他进程读写
    5.     NULL,                                                    // 默认安全属性
    6.     OPEN_EXISTING,                                           // 只打开已存在的文件
    7.     FILE_ATTRIBUTE_NORMAL,                              // 使用标准属性
    8.     NULL                                                    // 不使用模板
    9. );
    10. if (hFile == INVALID_HANDLE_VALUE) {
    11.     BeaconPrintf(CALLBACK_ERROR, "[-] can not open file: %s", filepath);
    12.     return;
    13. }
    复制代码

    时间戳修改

    最后使用SetFileTime​修改三个时间属性:创建时间、访问时间、修改时间。结束后关闭句柄。
    1. if (!KERNEL32$SetFileTime(hFile, &ft, &ft, &ft)) {
    2.     BeaconPrintf(CALLBACK_ERROR, "[-] failed to change timestamp");
    3. } else {
    4.     BeaconPrintf(CALLBACK_OUTPUT, "[+] success: %s", filepath);
    5. }
    6. KERNEL32$CloseHandle(hFile);
    复制代码
    这样就简单完成了修改一个文件时间戳的功能,完整代码如下:
    1. #include <stdio.h>
    2. #include <Windows.h>
    3. #include "beacon.h"
    4. // 声明Windows API函数
    5. DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetFileTime(HANDLE, const FILETIME*, const FILETIME*, const FILETIME*);
    6. DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileA(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
    7. DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle(HANDLE);
    8. DECLSPEC_IMPORT VOID WINAPI KERNEL32$GetSystemTime(LPSYSTEMTIME);
    9. DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SystemTimeToFileTime(LPSYSTEMTIME, LPFILETIME);
    10. void go(char* buff, int len) {
    11.     datap parser;
    12.     char* filepath;
    13.     BeaconDataParse(&parser, buff, len);
    14.     filepath = BeaconDataExtract(&parser, NULL);
    15.     if (!filepath) {
    16.         BeaconPrintf(CALLBACK_ERROR, "[-] please provide file path");
    17.         return;
    18.     }
    19.     SYSTEMTIME st;
    20.     FILETIME ft;
    21.     KERNEL32$GetSystemTime(&st);
    22.     st.wYear = 2020;
    23.     st.wMonth = 1;
    24.     st.wDay = 1;
    25.     st.wHour = 0;
    26.     st.wMinute = 0;
    27.     st.wSecond = 0;
    28.     KERNEL32$SystemTimeToFileTime(&st, &ft);
    29.     HANDLE hFile = KERNEL32$CreateFileA(
    30.         filepath,
    31.         FILE_WRITE_ATTRIBUTES,
    32.         FILE_SHARE_READ | FILE_SHARE_WRITE,
    33.         NULL,
    34.         OPEN_EXISTING,
    35.         FILE_ATTRIBUTE_NORMAL,
    36.         NULL
    37.     );
    38.     if (hFile == INVALID_HANDLE_VALUE) {
    39.         BeaconPrintf(CALLBACK_ERROR, "[-] can not open file: %s", filepath);
    40.         return;
    41.     }
    42.     if (!KERNEL32$SetFileTime(hFile, &ft, &ft, &ft)) {
    43.         BeaconPrintf(CALLBACK_ERROR, "[-] failed to change timestamp");
    44.     }
    45.     else {
    46.         BeaconPrintf(CALLBACK_OUTPUT, "[+] sunccess: %s", filepath);
    47.     }
    48.     KERNEL32$CloseHandle(hFile);
    49. }
    复制代码

    测试

    编译还是同上使用批天生,我这里测试的可以成功修改:


    优化编译

    为了更好的在苛刻环境下使用,我想继续压缩体积,找到的参数以及解释如下:

    • -Os: 优化巨细(比-O2天生更小的代码)
    • -fno-asynchronous-unwind-tables: 禁用异常睁开表
    • -fno-ident: 删除编译器版本信息
    • -fpack-struct=8: 结构体8字节对齐
    • -falign-functions=1: 函数1字节对齐
    • -s: 删除符号表
    • -ffunction-sections: 每个函数放入单独的段
    • -fdata-sections: 每个数据项放入单独的段
    • -fno-exceptions: 禁用异常处理
    • -fno-stack-protector: 禁用栈保护
    • -mno-stack-arg-probe: 禁用栈探测
    64位使用的编译命令如下:
    1. x86_64-w64-mingw32-gcc-8.1.0.exe -c .\Source.c -o timestamp.o -Os -fno-asynchronous-unwind-tables -fno-ident -fpack-struct=8 -falign-functions=1 -s -ffunction-sections -fdata-sections -fno-exceptions -fno-stack-protector -mno-stack-arg-probe
    复制代码
    针对于编译32位版本的命令( 如果没有就用批天生, 重命名即可):
    1. i686-w64-mingw32-gcc-8.1.0.exe -c .\Source.c -o timestamp.x86.o -Os -fno-asynchronous-unwind-tables -fno-ident -fpack-struct=8 -falign-functions=1 -s -ffunction-sections -fdata-sections -fno-exceptions -fno-stack-protector -mno-stack-arg-probe
    复制代码
    注:这里天生的是.o而不是.obj只是自己的需求为了同一一下,obj是Windows平台的默认目标文件扩展名,而.o是Unix/Linux平台的扩展名。它们本质和功能上是一样的,只是命名习惯不同。

    最后

    这里只是简单的示例,要使用最好要有一个锚定文件,以他的时间作为目标来修改。细节不赘述,详细请跳转Github。最终版本的使用测试如下:


    参考


    免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
  • 本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    x
    回复

    使用道具 举报

    0 个回复

    倒序浏览

    快速回复

    您需要登录后才可以回帖 登录 or 立即注册

    本版积分规则

    道家人

    金牌会员
    这个人很懒什么都没写!

    标签云

    快速回复 返回顶部 返回列表