[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);
}

第一次解密后

 再次解密

原文地址:https://www.cnblogs.com/harmonica11/p/13534374.html