模板配置

跟着网上的教程使用evilashz师傅的模板,下载模板解压至vs的模板目录:

%UserProfile%\Documents\Visual Studio 2022\Templates\ProjectTemplates

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

环境适配

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

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

但是一进来模板会报错没有引入库, 干脆就用最小测试代码:将 Source.cpp​重名为Source.c​并修改为如下:

#include <stdio.h>
#include <Windows.h>
#include "beacon.h"
void go(char* buff, int len) {
BeaconPrintf(CALLBACK_OUTPUT, "Hello BOF");
}

编译配置

在上方的生成中勾选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");​。

#include <stdio.h>
#include <Windows.h>
#include "beacon.h" #define INFO_FORMAT(fmt, ...) BeaconPrintf(CALLBACK_OUTPUT, "[*] " fmt "\n", ##__VA_ARGS__) void go(char* buff, int len) {
INFO_FORMAT("Hello BOF");
}

原先的内存中可能是这样:"Hello BOF" <未知内存内容>​,但使用宏之后就是这样的:"[*] Hello BOF\n" <确定的字符串终止>​,最后测试也没有乱码了。

功能实现

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

Windows API声明

要修改文件时间戳, 就要用到SetFileTime​。它用于设置文件的创建时间、访问时间和修改时间。文档中原型如下:

BOOL SetFileTime(
[in] HANDLE hFile,
[in, optional] const FILETIME *lpCreationTime,
[in, optional] const FILETIME *lpLastAccessTime,
[in, optional] const FILETIME *lpLastWriteTime
);

  • hFile: 文件句柄,必须有FILE_WRITE_ATTRIBUTES访问权限
  • lpCreationTime: 文件的创建时间
  • lpLastAccessTime: 文件的最后访问时间
  • lpLastWriteTime: 文件的最后修改时间

那么在bof的声明中要注意这个函数是属于哪个dll, 比如这里是kernel32.dll​的话那要定义和调用它时就写成KERNEL32$SetFileTime​,完整如下:

DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetFileTime(HANDLE, const FILETIME*, const FILETIME*, const FILETIME*);

cs使用这种前缀可以让BOF直接调用DLL中的原生函数, 就不需要再在导入表中声明了,这样也可以缩小BOF体积。类似的使用CreateFileA​来创建或打开文件时, 其原型如下:

HANDLE CreateFileA(
[in] LPCSTR lpFileName, // 文件名
[in] DWORD dwDesiredAccess, // 访问模式
[in] DWORD dwShareMode, // 共享模式
[in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全描述符
[in] DWORD dwCreationDisposition, // 创建方式
[in] DWORD dwFlagsAndAttributes, // 文件属性
[in, optional] HANDLE hTemplateFile // 模板文件句柄
);

BOF中声明则如下:

DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileA(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);

以及其他要用到的api可以这样声明:

// 其他必要的API
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle(HANDLE); // 关闭一个内核对象(如文件)的句柄
DECLSPEC_IMPORT VOID WINAPI KERNEL32$GetSystemTime(LPSYSTEMTIME); // 获取当前系统时间(UTC时间)
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SystemTimeToFileTime(LPSYSTEMTIME, LPFILETIME); // 将SYSTEMTIME结构转换为FILETIME结构。

参数处理

BOF的入口函数就是这里的go, inline-execute​执行BOF时先调用这个。其中先定义并初始化一个解析器来解析传入的参数,timestamp​这个至少也是要一个参数路径的,先从一个来:

void go(char* buff, int len) {
datap parser;
char* filepath; // 解析Beacon传入的参数
BeaconDataParse(&parser, buff, len);
filepath = BeaconDataExtract(&parser, NULL); // 参数验证
if (!filepath) {
BeaconPrintf(CALLBACK_ERROR, "[-] please provide file path");
return;
}
}

那解析多个参数呢, 一样的:

BeaconDataParse(&parser, buff, len);
sourceFile = BeaconDataExtract(&parser, NULL);
targetFile = BeaconDataExtract(&parser, NULL); if (!sourceFile || !targetFile) {
BeaconPrintf(CALLBACK_ERROR, "[!] Error: Two file paths required\n");
BeaconPrintf(CALLBACK_ERROR, "[-] Usage: inline-execute timestamp.o \"source_file\" \"target_file\"\n");
return;
} BeaconPrintf(CALLBACK_OUTPUT, "[-] Source: %s\n", sourceFile);
BeaconPrintf(CALLBACK_OUTPUT, "[-] Target: %s\n", targetFile);

时间处理

接着继续,获取系统时间然后修改成我们希望的时间,比如2020年1月1日 00:00:00​。然后把他转换为文件时间格式:

SYSTEMTIME st;
FILETIME ft;
KERNEL32$GetSystemTime(&st); st.wYear = 2020;
st.wMonth = 1;
st.wDay = 1;
st.wHour = 0;
st.wMinute = 0;
st.wSecond = 0; KERNEL32$SystemTimeToFileTime(&st, &ft);

文件操作

准备好了要修改的时间后就尝试打开文件获取句柄:

HANDLE hFile = KERNEL32$CreateFileA(
filepath, // 文件路径
FILE_WRITE_ATTRIBUTES, // 只需要写属性权限
FILE_SHARE_READ | FILE_SHARE_WRITE, // 允许其他进程读写
NULL, // 默认安全属性
OPEN_EXISTING, // 只打开已存在的文件
FILE_ATTRIBUTE_NORMAL, // 使用标准属性
NULL // 不使用模板
); if (hFile == INVALID_HANDLE_VALUE) {
BeaconPrintf(CALLBACK_ERROR, "[-] can not open file: %s", filepath);
return;
}

时间戳修改

最后使用SetFileTime​修改三个时间属性:创建时间、访问时间、修改时间。结束后关闭句柄。

if (!KERNEL32$SetFileTime(hFile, &ft, &ft, &ft)) {
BeaconPrintf(CALLBACK_ERROR, "[-] failed to change timestamp");
} else {
BeaconPrintf(CALLBACK_OUTPUT, "[+] success: %s", filepath);
} KERNEL32$CloseHandle(hFile);

这样就简单完成了修改一个文件时间戳的功能,完整代码如下:

#include <stdio.h>
#include <Windows.h>
#include "beacon.h" // 声明Windows API函数
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetFileTime(HANDLE, const FILETIME*, const FILETIME*, const FILETIME*);
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileA(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle(HANDLE);
DECLSPEC_IMPORT VOID WINAPI KERNEL32$GetSystemTime(LPSYSTEMTIME);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SystemTimeToFileTime(LPSYSTEMTIME, LPFILETIME); void go(char* buff, int len) {
datap parser;
char* filepath; BeaconDataParse(&parser, buff, len);
filepath = BeaconDataExtract(&parser, NULL); if (!filepath) {
BeaconPrintf(CALLBACK_ERROR, "[-] please provide file path");
return;
} SYSTEMTIME st;
FILETIME ft;
KERNEL32$GetSystemTime(&st); st.wYear = 2020;
st.wMonth = 1;
st.wDay = 1;
st.wHour = 0;
st.wMinute = 0;
st.wSecond = 0; KERNEL32$SystemTimeToFileTime(&st, &ft); HANDLE hFile = KERNEL32$CreateFileA(
filepath,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
); if (hFile == INVALID_HANDLE_VALUE) {
BeaconPrintf(CALLBACK_ERROR, "[-] can not open file: %s", filepath);
return;
} if (!KERNEL32$SetFileTime(hFile, &ft, &ft, &ft)) {
BeaconPrintf(CALLBACK_ERROR, "[-] failed to change timestamp");
}
else {
BeaconPrintf(CALLBACK_OUTPUT, "[+] sunccess: %s", filepath);
} KERNEL32$CloseHandle(hFile);
}

测试

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

优化编译

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

  • -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位使用的编译命令如下:

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位版本的命令( 如果没有就用批生成, 重命名即可):

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。最终版本的使用测试如下:

参考

BOF编写-修改时间戳的更多相关文章

  1. 学习Shell脚本编程(第2期)_编写修改权限及执行Shell程序的步骤

    编写Shell程序 执行Shell程序 Shell程序有很多类似C语言和其他程序设计语言的特征,但是又没有程序语言那样复杂.Shell程序是指放在一个文件中的一系列Linux命令和实用程序.在执行的时 ...

  2. linux下修改时间戳

    Linux下touch是一个非常有用的命令. touch语法结构如下: touch [-acfm][-d <日期时间>][-r <参考文件或目录>][-t <日期时间&g ...

  3. 创建文件和修改时间戳——touch

    linux的touch命令不常用,一般在使用make的时候可能会用到,用来修改文件时间戳,或者新建一个不存在的文件. 1.命令格式: touch [选项]... 文件... 2.命令参数: -a    ...

  4. 2、编写/修改权限及执行Shell程序的步骤

    学习目标编写Shell程序执行Shell程序 正文Shell程序有很多类似C语言和其他程序设计语言的特征,但是又没有程序语言那样复杂.Shell程序是指放在一个文件中的一系列Linux命令和实用程序. ...

  5. Nginx修改时间戳

    1.安装nginx,注意不要安装nginx-common或者nginx-full sudo apt-get install nginx sudo apt-get install nginx-commo ...

  6. 安卓脱壳&&协议分析&&burp辅助分析插件编写

    前言 本文由 本人 首发于 先知安全技术社区: https://xianzhi.aliyun.com/forum/user/5274 前言 本文以一个 app 为例,演示对 app脱壳,然后分析其 协 ...

  7. 学习 Linux,101: 自定义或编写简单脚本【转】

    转自:http://www.ibm.com/developerworks/cn/linux/l-lpic1-105-2/index.html 学习如何使用标准的 shell 语法.循环和控制结构,以及 ...

  8. 【实战Java高并发程序设计 3】带有时间戳的对象引用:AtomicStampedReference

    [实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference AtomicReference无法解决上述问题的根 ...

  9. SQL时间戳的使用

    SQL时间戳的使用 一直对时间戳这个概念比较模糊,相信有很多朋友也都会误认为:时间戳是一个时间字段,每次增加数据时,填入当前的时间值.其实这误导了很多朋友. 1.基本概念 时间戳:数据库中自动生成的唯 ...

  10. ADO.NET(完整修改和查询、实体类,数据访问类)

    一.完整修改和查询 在编写c#语句时需考虑到用户体验,例如在编写修改语句时,需要考虑到输入的内容在数据库中是否能够找到. 中间变量运用. 1.先查 2.执行操作 完整修改语句: bool has = ...

随机推荐

  1. 借用Ultralytics Yolo快速训练一个物体检测器

    借用Ultralytics Yolo快速训练一个物体检测器 同步发表于 https://www.codebonobo.tech/post/14 大约在16/17年, 深度学习刚刚流行时, Object ...

  2. Golang 开源库分享:anko - 给 Go 加点“脚本魔法”

    GitHub 仓库链接:https://github.com/mattn/anko 1. anko 是干嘛用的? anko 是一个可以让 Go 项目支持脚本语言的小工具.换句话说,就是我们可以给 Go ...

  3. IntelliJ IDEA 2024激活码(亲测有效,仅供学习和交流)

    资源是从官网购买,仅供学习和交流 激活码链接地址

  4. vim粘贴文件格式不乱

    vim粘贴防止格式乱,配置以下命令然后在粘贴,即可~ :set paste

  5. STM32F103RCT6搭配“ST_LINK V2 √RoHS 'A 2023 04'”在CubeIDE中下载程序到单片机

    一.请参考本站大佬文章进行接线: ST_LINK V2接口和连接方式 二.步骤: 到此,大功告成. 小手点赞,水逆退散!!!

  6. 一款WPF开发的B站视频下载开源项目

    更多开源项目请查看:一个专注推荐优秀.Net开源项目的榜单 今天给推荐一款C#开发的.界面简洁的哔哩哔哩视频下载工具. 项目简介 这是一款基于WPF开发的,B站下载工具,操作界面简洁,支持多线程下载. ...

  7. 现代IT基础设施管理(1):Terraform初识和小试牛刀

    基础设施包括各种云,像国内的阿里云.腾讯云和华为云,国外的AWS.微软Azure云和谷歌云,还有Kubernetes和OpenStack,都可以用Terraform进行资源管理.使用基础设施即代码(I ...

  8. 有经验的Java开发者和架构师容易犯的10个错误

    本文由 ImportNew - Andy.Song 翻译自 zeroturnaround.如需转载本文,请先参见文章末尾处的转载要求. 首先允许我们问一个严肃的问题?为什么Java初学者能够方便的从网 ...

  9. 解码OutOfMemoryError:PermGen Space

    本文由 ImportNew - Peter Pan 翻译自 javacodegeeks.如需转载本文,请先参见文章末尾处的转载要求. ImportNew注:如果你也对Java技术翻译分享感兴趣,欢迎加 ...

  10. java——棋牌类游戏五子棋(webwzq1.0)之一(基础)

    这是本人最近一段时间写的斗地主的java代码,大体框架都实现了,一些细节还需要后续优化. package basegame; import java.awt.Button; import java.a ...