[FlareOn6]BMPHIDE
一个net程序和一张bmp
用dnspy看看
private static void Main(string[] args)
{
Program.Init();
Program.yy += 18;
string filename = args[2];
string fullPath = Path.GetFullPath(args[0]);
string fullPath2 = Path.GetFullPath(args[1]);
byte[] data = File.ReadAllBytes(fullPath2);
Bitmap bitmap = new Bitmap(fullPath);
byte[] data2 = Program.h(data);
Program.i(bitmap, data2);
bitmap.Save(filename);
}
调试发现,Init会触发一个异常
跟进去发现有个
进去看看
public static void CalculateStack()
{
Module module = typeof(A).Module;
ModuleHandle moduleHandle = module.ModuleHandle;
A.ver4 = (Environment.Version.Major == 4);
bool flag = A.ver4;
if (flag)
{
A.ver5 = (Environment.Version.Revision > 17020);
}
A.IdentifyLocals();
}
进入A.IdentifyLocals()
进入A.IncrementMaxStack
看到将程序修改了
修改的部分为methodBase.MetadataToken == 100663317和methodBase.MetadataToken == 100663316,通过
可得知一个是h(),另一个是g()
根据 A.IncrementMaxStack里的方式修改程序
public static byte g(int idx)//改前
{
byte b = (byte)((long)(idx + 1) * (long)((ulong)-306674912));
byte k = (byte)((idx + 2) * 1669101435);
return Program.e(b, k);
}
public static byte g(int idx)//改后
{
byte b = (byte)((long)(idx + 1) * (long)((ulong)309030853));
byte k = (byte)((idx + 2) * 209897853);
return Program.e(b, k);
}
public static byte[] h(byte[] data)//改前
{
byte[] array = new byte[data.Length];
int num = 0;
for (int i = 0; i < data.Length; i++)
{
int num2 = (int)Program.f(num++);
int num3 = (int)data[i];
num3 = (int)Program.e((byte)num3, (byte)num2);
num3 = (int)Program.a((byte)num3, 7);
int num4 = (int)Program.f(num++);
num3 = (int)Program.e((byte)num3, (byte)num4);
num3 = (int)Program.c((byte)num3, 3);
array[i] = (byte)num3;
}
return array;
}
public static byte[] h(byte[] data)//改后
{
byte[] array = new byte[data.Length];
int num = 0;
for (int i = 0; i < data.Length; i++)
{
int num2 = (int)Program.g(num++);
int num3 = (int)data[i];
num3 = (int)Program.e((byte)num3, (byte)num2);
num3 = (int)Program.a((byte)num3, 7);
int num4 = (int)Program.g(num++);
num3 = (int)Program.e((byte)num3, (byte)num4);
num3 = (int)Program.c((byte)num3, 3);
array[i] = (byte)num3;
}
return array;
}
修改之后将Init里A.CalculateStack()修改IL指令为nop后保存模块,要在md写入中勾选
之后就可以调试了,回头看main,重点在
分析可发现这是一个隐写,隐写的数据在被h处理后经过i写入图片
public static void i(Bitmap bm, byte[] data)
{
int num = Program.j(103);
for (int i = Program.j(103); i < bm.Width; i++)
{
for (int j = Program.j(103); j < bm.Height; j++)
{
bool flag = num > data.Length - Program.j(231);
if (flag)
{
break;
}
Color pixel = bm.GetPixel(i, j);
int red = ((int)pixel.R & Program.j(27)) | ((int)data[num] & Program.j(228));
int green = ((int)pixel.G & Program.j(27)) | (data[num] >> Program.j(230) & Program.j(228));
int blue = ((int)pixel.B & Program.j(25)) | (data[num] >> Program.j(100) & Program.j(230));
Color color = Color.FromArgb(Program.j(103), red, green, blue);
bm.SetPixel(i, j, color);
num += Program.j(231);
}
}
}
这样基本就可以还原了,不过在Init里还有一处坑
调试可发现,这里将a()转为了b(),c()转为了d(),所以之前看到程序里对a和c的调用其实用的都是b和d
看一下这几个程序
public static byte b(byte b, int r)
{
for (int i = 0; i < r; i++)
{
byte b2 = (b & 128) / 128;
b = (b * 2 & byte.MaxValue) + b2;
}
return b;
}
public static byte d(byte b, int r)
{
for (int i = 0; i < r; i++)
{
byte b2 = (b & 1) * 128;
b = (b / 2 & byte.MaxValue) + b2;
}
return b;
}
public static byte g(int idx)
{
byte b = (byte)((long)(idx + 1) * (long)((ulong)309030853));
byte k = (byte)((idx + 2) * 209897853);
return Program.e(b, k);
}
public static byte e(byte b, byte k)
{
for (int i = 0; i < 8; i++)
{
bool flag = (b >> i & 1) == (k >> i & 1);
if (flag)
{
b = (byte)((int)b & ~(1 << i) & 255);
}
else
{
b = (byte)((int)b | (1 << i & 255));
}
}
return b;
}
b和d是循环移位的操作,e就是个xor,g是个hash,j返回的值是固定的可以直接调出来
之后可以借助这个程序改为解密算法
private static void Main(string[] args)
{
Program.Init();
Program.yy += 18;
Bitmap bitmap = new Bitmap(args[0]);
byte[] output = new byte[bitmap.Width * bitmap.Height];
int outidx = 0;
int hashCtr = 0;
for (int i = 0; i < bitmap.Width; i++)
{
for (int j = 0; j < bitmap.Height; j++)
{
Color pixel = bitmap.GetPixel(i, j);
byte r = pixel.R & 7;
byte g = pixel.G & 7;
byte b = (byte)((int)(pixel.B & 3) << 6 | (int)g << 3 | (int)r);
byte g2 = Program.g(hashCtr++);
byte g3 = Program.g(hashCtr++);
byte newByte = Program.a(b, 3);
newByte ^= g3;
newByte = Program.c(newByte, 7);
newByte ^= g2;
output[outidx++] = newByte;
}
}
File.WriteAllBytes(args[1], output);
}
第一次解密后
再次解密