-
-
[原创]看雪 2016 CTF 第二十三 像素扫描
-
发表于: 2016-12-17 17:33 5716
-
程序入口Hi_main_sub_4016B0函数定位窗体相应函数 Hi_DialogFunc_sub_401830
Hi_main_sub_4016B0
.text:004016D7 push offset Hi_DialogFunc_sub_401830 ; lpDialogFunc
.text:004016DC push 0 ; hWndParent
.text:004016DE push 65h ; lpTemplateName
.text:004016E0 push esi ; hInstance
.text:004016E1 call ds:CreateDialogParamW
响应函数Hi_DialogFunc_sub_401830分两步
Hi_getKey_sub_401140 获取注册码信息
Hi_checkKey_sub_4017B0 进入校验环节
Hi_getKey_sub_401140获取的注册码信息是注册码字符在
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"中的零起索引数组
长度伪要求"004018BE cmp eax, 8"不小于8,实际要求固定长度0x12
注册码信息的获取比较特殊,Hi_Hook_GetBoundsRect_sub_401000初始化函数劫持了
API函数 GetBoundsRect 如下,其实际调用为 Hi_GetBoundsRect_sub_401350 函数
而Hi_GetBoundsRect_sub_401350函数的实际作用通过异常转换为 GetPixel 调用
pxyRGB = GetPixel(hdcOfEdit,ch_lt_X+ch_in_x,ch_lt_Y+ch_in_y)
Edit框的字体信息为
CreateFontW(20, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 0x31u, L"Courier New")
每一个字符的像素矩阵为0x08*0x0E=0x70
Hi_getKey_sub_401140函数通过GetPixel(以GetBoundsRect为伪装)依次扫描
Edit输入框的0x12个字符的像素矩阵0x08*0x0E=0x70,
字符的像素特征矩阵分别以[0x00,0xFF]之间的随机偶数和奇数描述,
若像素为白素则描述为随机偶数,否则描述为随机奇数
没获取一个字符的像素特征奇偶数矩阵,就会通过
Hi_search_oepa_for_char_in_oepas_sub_4010A0函数进行查表得到字符的索引值,
Hi_oepas_of_09azAZ_byte_4121C0静态依次存储了
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"字符
的像素特征随机奇偶数表示的矩阵,查表时,只有目标矩阵个像素的奇偶数特征都匹配时
则匹配成功。
GetBoundsRect劫持
BOOL Hi_Hook_GetBoundsRect_sub_401000()
{
flOldProtect = 0;
VirtualProtect(GetBoundsRect, 5u, 4u, &flOldProtect);
memcpy_s(&Hi_GetBoundsRect_Head5bytes_dword_414A84, 5u, GetBoundsRect, 5u);
LongJmpBuf.OpCode = 0xE9 //jmp
LongJmpBuf.Offset = Hi_GetBoundsRect_sub_401350 - GetBoundsRect - 5;
memcpy_s(GetBoundsRect, 5u, &LongJmpBuf, 5u);
result = VirtualProtect(GetBoundsRect, 5u, flOldProtect, &flOldProtect);
return result;
}
注册码信息获取函数伪码
Hi_getKey_sub_401140(key) //扫描Edit输入框像素矩阵获取注册码信息
{
hdcOfEdit = GetDC(hWndOfEdit_414A98)
ch_lt_X=3,ch_lt_Y=4;
ch_idx = 0
while True:
ch_in_y = 0
while True:
ch_in_x = 0
while True:
pxyRGB = GetPixel(hdcOfEdit,ch_lt_X+ch_in_x,ch_lt_Y+ch_in_y)
//GetBoundsRect(hdcOfEdit,ch_lt_X+ch_in_x,ch_lt_Y+ch_in_y)
//GetBoundsRect Longjmp to Hi_GetBoundsRect_sub_401350
if pxyRGB == WHILE.0x00FFFFFF: //如果像素为白色则以随机偶数表示
oev = ptd.rand.even inner 0xff
else:
oev = ptd.rand.odd inner 0xff //否则以随机偶数奇数表示
oepa_of_char[ch_in_y*0x8+ch_in_x] = oev
if ++ch_in_x >= 8:break
if ++ch_in_y >= 0x0E:break
ch_lt_X+=0x0A //next char left-top pixel x-pos
key[ch_idx] = Hi_search_oepa_for_char_in_oepas_sub_4010A0(oepa_of_char)
if ++ch_idx >= 0x12:break
return key
}
字符像素特征奇偶数矩阵查表
Hi_search_oepa_for_char_in_oepas_sub_4010A0(oepa_of_char){
//CharIndex is index of "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
//e.g. CharIndex.0x00 for "0"; CharIndex.0x10 for "g";
for CharIndex in xrange(0,0x3E):
oepaX = Hi_oepas_of_09azAZ_byte_4121C0[CharIndex]
if Is_Odd_Even_Attrib_Of_Each_Element_All_Match(oepaX,oepa_of_char):
return CharIndex
}
如字符表中第一个字符"0"的像素特殊奇偶数矩阵
for i in xrange(0,0x70):
print "{:02X}".format(Byte(0x4121c0+i)),
if (i+1)%8==0:
print
D5 88 18 28 26 D0 5E 25
6D 48 3E 58 F6 CC C6 2D
C2 C0 E8 6C 5C 4C CE 22
F8 2E 8A DF C5 CE D8 F0
16 4C 30 C1 A3 C4 B0 F0
2C C2 F4 75 63 94 4E 52
E2 20 5A 95 85 3C 7A B0
00 96 E4 59 45 F6 18 12
D4 6E 64 C8 74 7C 00 C6
B7 58 1C E4 92 2C 28 4D
87 5A CA 88 4C 98 32 F1
CD 69 53 47 6F 13 E7 97
DB 93 4B 57 AD EB 8F 4D
D9 29 5D 93 B7 D3 49 33
通过下述代码,我们观察奇偶数矩阵的像素特征
def oec(cv=0,o=" ",e="1"):
if cv & 1:
return o
else:
return e
def gsc(ea,bp = False):
nca = []
ln = ""
for i in xrange(0,0x70):
#print oec(Byte(ea+i)),
ln += oec(Byte(ea+i))
if (i+1)%8==0:
if bp:
print ln
nca.append(ln)
ln = ""
if bp:
print ln
nca.append(ln)
return nca
def sncas(ncas):
for r in xrange(0,ncas[0].__len__()):
for nca in ncas:
print nca[r],
print
print "-"*0x80
sncas([gsc(0x4121c0)])
print "-"*0x80
上述代码通过oec分别以" "和"1"描述奇偶数,得到字符的像素矩阵的形象特征图形
--------------------------------------------------------------------------------------------------------------------------------
111111
111111
11111111
111 111
111 111
111 111
111 111
111 111
11111111
111111
111111
--------------------------------------------------------------------------------------------------------------------------------
allnca = []
for i in xrange(0,0x3E):
nca_ea = 0x4121C0 + i*0x70
allnca.append(gsc(nca_ea))
print "-"*0x80
sncas(allnca[0:0x0a])
print "-"*0x80
sncas(allnca[0x0A:0x0A+0x0E])
print "-"*0x80
sncas(allnca[26+0x0A:0x0A+0x0E+26])
print "-"*0x80
--------------------------------------------------------------------------------------------------------------------------------
111111 1111 111111 111111 1111 11111111 11111 11111111 111111 11111
111111 111111 11111111 11111111 11111 11111111 111111 11111111 11111111 1111111
11111111 111111 111 111 111 111 11111 111 1111 111 111 111 111 1111 111
111 111 1111 111 111 111 111111 111 1111 111 111 111 111 11
111 111 1111 1111 111111 111111 1111111 1111111 111 11111111 1111 111
111 111 1111 1111 111111 1111111 11111111 11111111 111 11111111 1111111
111 111 1111 1111 111 11111111 111 1111 111 111 111 111 111111
111 111 1111 1111 111 11111111 111 111 11 111 111 111 111
11111111 1111 1111 11 111 111 11 111 1111 111 111 111 111 1111
111111 11111111 11111111 11111111 111111 11111111 1111111 111 11111111 1111111
111111 11111111 11111111 1111111 111111 111111 11111 111 111111 111111
--------------------------------------------------------------------------------------------------------------------------------
111 1111 11111 111 111 111 111 111111
111 1111 111111 111 111 111 111 111111
111 111 111 111 111 1111
1111111 1111111 1111111 1111111 111111 11111111 1111111 1111111 111111 1111111 11111111 1111 11111111 1111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 111111 1111111 11111111 1111 11111111 11111111
111 1111 111 111 11 111 111 111 111 111 111 1111 1111 111 1111 111 111111 1111 11111111 1111 111
1111111 111 11 11 11 111 11111111 111 11 111 111 111 1111 111 11111 1111 11 11111 111 111
11111111 111 11 11 11 111 11111111 111 11 111 111 111 1111 111 111111 1111 11 11 11 111 111
11 111 111 111 111 11 111 111 11 111 111 1111 111 111 1111 111 1111111 1111 11 11 11 111 111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 111 111 1111 11111111 11 11111 11111111
11111111 1111111 1111111 1111111 1111111 11111111 1111111 11111111 11111111 111 11111111 11111111 11 11111 11111111
111 111
1111111 1111111
111111 111111
--------------------------------------------------------------------------------------------------------------------------------
111111 1111111 1111111 1111111 11111111 11111111 1111111 11111111 11111111 111111 11111111 111111 111 111 111 111
111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 111111 11111111 111111 111 111 1111 111
111111 111 111 111 111 111 111 111 111 1111 11 111 11 111 111 1111 111 111 111 111 111 111 1111 111
111111 111 111 11 11 111 111 11111111 11111111 11 111 111 1111 111 111111 111 11111111 11111111
1111111 11111111 11 111 11 111111 111111 11 11111111 1111 111 111111 111 11111111 11111111
11111111 11111111 11 111 11 111111 111111 11 1111 11111111 1111 11 111 1111111 111 11 11111111 11111111
11111111 111 11 11 111 11 11111111 111111 11 1111 111 111 1111 11 111 111 1111 111 11 11111111 11111111
111 111 111 11 111 11 111 111 111 11 1111 111 11 111 111 1111 111 1111 111 111 111 11 11 11111 111 1111
11111111 11111111 11111111 11111111 11111111 111111 11111111 11111111 11111111 1111111 1111 111 11111111 11111111 111 1111
11111111 11111111 1111111 1111111 11111111 111111 1111111 11111111 11111111 11111 1111 11 11111111 11111111 111 111
--------------------------------------------------------------------------------------------------------------------------------
.text:0040189D lea edx, [esp+40h+var_18_key]
.text:004018A1 mov [esp+40h+var_18_key], 0
.text:004018A6 movdqu xmmword ptr [esp+40h+var_18_key+1], xmm0
.text:004018AC push ecx
.text:004018AD mov word ptr [esp+44h+var_18_key+11h], 0
.text:004018B4 mov [esp+44h+var_5], 0
.text:004018B9 call Hi_getKey_sub_401140
.text:004018BE cmp eax, 8
.text:004018C1 jb loc_401960
.text:004018C7 lea ecx, [esp+40h+var_18_key]
.text:004018CB call Hi_checkKey_sub_4017B0
.text:004018D0 cmp eax, 0A466EEEFh
Hi_checkKey_sub_4017B0
.text:004017B0 Hi_checkKey_sub_4017B0 proc near ; CODE XREF: Hi_DialogFunc_sub_401830+9Bp
.text:004017B0 push ebx
.text:004017B1 push esi
.text:004017B2 mov esi, ecx
.text:004017B4 mov al, [esi]
.text:004017B6 movzx edx, byte ptr [esi+1]
.text:004017BA not al
.text:004017BC movzx ecx, byte ptr [esi+2]
.text:004017C0 movzx eax, al
.text:004017C3 mov ebx, dword ptr Hi_oepas_of_09azAZ_byte_4121C0[eax*4]
.text:004017CA xor ebx, 0FFFh
.text:004017D0 movzx eax, bl
.text:004017D3 xor edx, eax
.text:004017D5 shr ebx, 8
.text:004017D8 xor ebx, dword ptr Hi_oepas_of_09azAZ_byte_4121C0[edx*4]
.text:004017DF movzx eax, bl
.text:004017E2 xor ecx, eax
.text:004017E4 shr ebx, 8
.text:004017E7 xor ebx, dword ptr Hi_oepas_of_09azAZ_byte_4121C0[ecx*4]
.text:004017EE movzx ecx, byte ptr [esi+3]
.text:004017F2 movzx eax, bl
.text:004017F5 xor ecx, eax
.text:004017F7 shr ebx, 8
.text:004017FA xor ebx, dword ptr Hi_oepas_of_09azAZ_byte_4121C0[ecx*4]
.text:00401801 cmp dword ptr [esi+4], 0E361C2Ch
.text:00401808 jnz short loc_401827
.text:0040180A cmp dword ptr [esi+8], 150A121Bh
.text:00401811 jnz short loc_401827
.text:00401813 cmp dword ptr [esi+0Ch], 0B161E31h
.text:0040181A jnz short loc_401827
.text:0040181C cmp dword ptr [esi+10h], 1B0Eh
.text:00401823 jnz short loc_401827
.text:00401825 not ebx
.text:00401827
.text:00401827 loc_401827:
.text:00401827 pop esi
.text:00401828 mov eax, ebx
.text:0040182A pop ebx
.text:0040182B retn
.text:0040182B Hi_checkKey_sub_4017B0 endp
byte key[0x12] = {k0,k1,k2,k3,...,k16,k17} = {ww1,ww2,ww3,ww4,w5}
其中 ww2 = 0E361C2Ch;ww3 = 150A121Bh;ww4 = 0B161E31h;w5 = 1B0Eh
即 key417 = k4,k5,...,k17 = {ww2,ww3,ww4,w5}
于是执行下述#-------python代码得到key417_str为"IsSerialNumber"
#-------
key417 =[0x2C,0x1C,0x36,0x0E,0x1B,0x12,0x0A,0x15,0x31,0x1e,0x16,0x0b,0x0e,0x1b]
nazAZ = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
key417_str = b"".join([nazAZ[CharIndex] for CharIndex in key417])
#-------
key的前四字节的校验逻辑为
ebx = Hi_oepas_of_09azAZ_byte_4121C0[~k0]
ebx ^= 0xFFF
dl = k1 ^ bl
ebx >> 8
ebx ^= Hi_oepas_of_09azAZ_byte_4121C0[dl]
cl = k2 ^ bl
ebx >> 8
ebx ^= Hi_oepas_of_09azAZ_byte_4121C0[cl]
cl = k3 ^ bl
ebx >> 8
ebx ^= Hi_oepas_of_09azAZ_byte_4121C0[cl]
not ebx
ebx == 0x0A466EEEFh
直接的方式就是借助k0,k1,k2,k3的取值范围nazAZ
和数组Hi_oepas_of_09azAZ_byte_4121C0直接穷举
这里尝试从校验逻辑进行逆推
在最后一步异或操作中
cl = k3 ^ bl
ebx >> 8
ebx ^= Hi_oepas_of_09azAZ_byte_4121C0[cl]
其中异或结果为 ebx = not 0x0A466EEEFh = 0x5b991110
考虑到异或前ebx>>8,即最高位为0x00;
即cl取值范围[0,0xFF]取出的字的最高字节为 0x5b ^ 0x00 = 0x5b
#-------
def getidxwws(wwhb):
idxwws = []
for i in xrange(0,0x100):
if wwhb == Byte(0x4121C0+i*4+3):
ww = Dword(0x4121C0+i*4)
#print "{:02X} {:08X}".format(i,ww)
idxwws.append([i,ww])
return idxwws
def sidxwws(idxwws,bxor = None,pref=" "):
for iww in idxwws:
if bxor:
print "{:02X} {:08X} {:08X}".format(iww[0],iww[1],iww[1]^bxor)
else:
print "{:02X} {:08X}".format(iww[0],iww[1])
iwws1 = getidxwws(0x5b)
sidxwws(iwws1,0x5b991110)
#-------
-----------------------------------------
执行上面的脚本,我们可以得到cl和对应异或前ebx>>8的可能取值
cl ebx>>8
58 5BF43274 006D2364
BE 5BDDC935 0044D825
D0 5B1D07CB 008416DB
DC 5BEB9BAF 00728ABF
-----------------------------------------
同理往前逆推,下述cl选出的字最高位分别为上述ebx>>8确定的ebx最高位
可能取值为0x6d,0x44,0x84,0x72
cl = k2 ^ bl
ebx >> 8
ebx ^= Hi_oepas_of_09azAZ_byte_4121C0[cl]
执行
sidxwws(getidxwws(0x6d),0x006D2364<<8)
sidxwws(getidxwws(0x44),0x0044D825<<8)
sidxwws(getidxwws(0x84),0x008416DB<<8)
sidxwws(getidxwws(0x72),0x00728ABF<<8)
得到
58 5BF43274 006D2364
cl ebx>>8
43 6D407E70 00631A70
93 6D8D0BB9 00AE6FB9
BE 5BDDC935 0044D825
cl ebx>>8
22 4438BB05 00E09E05
8F 440C34F8 00D411F8
D0 5B1D07CB 008416DB ***不存在继续满足帅选的情形***
DC 5BEB9BAF 00728ABF ***不存在继续满足帅选的情形***
-----------------------------------------
同理往前逆推,下述cl选出的字最高位分别为上述ebx>>8确定的ebx最高位
可能取值为0x63,0xAE,0xE0,0xD4
dl = k1 ^ bl
ebx >> 8
ebx ^= Hi_oepas_of_09azAZ_byte_4121C0[dl]
执行
sidxwws(getidxwws(0x63),0x00631A70<<8)
sidxwws(getidxwws(0xAE),0x00AE6FB9<<8)
sidxwws(getidxwws(0xE0),0x00E09E05<<8)
sidxwws(getidxwws(0xD4),0x00D411F8<<8)
得到
58 5BF43274 006D2364
43 6D407E70 00631A70
dl ebx>>8
21 634D8C36 0057FC36
92 633CF238 00268238
CE 63615599 007B2599
DD 630B572D 0011272D
93 6D8D0BB9 00AE6FB9
dl ebx>>8
74 AE2A2F3F 0045963F
BE 5BDDC935 0044D825
22 4438BB05 00E09E05 ***不存在继续满足帅选的情形***
8F 440C34F8 00D411F8
dl ebx>>8
48 D4204AAC 0031B2AC
-----------------------------------------
同理往前逆推,下述cl选出的字最高位分别为上述ebx>>8确定的ebx最高位
可能取值为 0x57,0x26,0x7b,0x11,0x45,0x31
ebx = Hi_oepas_of_09azAZ_byte_4121C0[~k0]
ebx ^= 0xFFF
执行
sidxwws(getidxwws(0x57))
sidxwws(getidxwws(0x26))
sidxwws(getidxwws(0x7b))
sidxwws(getidxwws(0x11))
sidxwws(getidxwws(0x45))
sidxwws(getidxwws(0x31))
得到
~k0 ebx
18 574B93DB
E2 26C6667C
3E 7BEA78EA
6A 7B77D1ED
FA 7BD5254F
D7 31FB64A6
F8 3193FB8B
-----------------------------------------
有上述~k0的取值,我们可以得到相应的k0取值,
执行
not_k0 = [0x18,0xE2,0x3E,0x6A,0xFA,0xD7,0xF8]
for kt in not_k0:
print "0x{:02X}".format(c_ubyte(~kt).value),
得到~k0对应的k0取值
0xE7 0x1D 0xC1 0x95 0x05 0x28 0x07
由于k0为"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"索引
即k0,k1,k2,k3取值范围都为 [0,0x3D]
即得到k0的可能取值为 0x1D,0x05,0x28,0x07
-----------------------------------------
组合各次逆推过程
58 5BF43274 006D2364
43 6D407E70 00631A70
92 633CF238 00268238
E2 26C6667C k0 = ~0xE2 = 0x1D
CE 63615599 007B2599
FA 7BD5254F k0 = ~0xFA = 0x05
BE 5BDDC935 0044D825
8F 440C34F8 00D411F8
48 D4204AAC 0031B2AC
D7 31FB64A6 k0 = ~0xD7 = 0x28
F8 3193FB8B k0 = ~0xF8 = 0x07
-----------------------------------------
对于
58 5BF43274 006D2364
43 6D407E70 00631A70
92 633CF238 00268238
E2 26C6667C k0 = ~0xE2 = 0x1D
有k0=0x1d,dl=0x92,ebx=byte_4121C0[~k0] ^ 0xFFF = 0x26c66983 即bl=0x83
-------
ebx = byte_4121C0[~k0]
ebx ^= 0xFFF
dl = k1 ^ bl
所以k1 = bl ^ dl = 0x83 ^ 0x92 = 0x11 属于有效取值范围[0x00,0x0D]
-------
同理,对于
ebx ^= byte_4121C0[dl]
cl = k2 ^ bl
有cl=0x43,ebx=0x26c66983,dl=0x92
ebx ^= byte_4121C0[dl]
后有ebx=0x631a3451,
所以k2 = bl ^ cl = 0x51 ^ 0x43 = 0x12 属于有效取值范围[0x00,0x0D]
-------
同理,对于
(1):ebx ^= byte_4121C0[cl]
(2):cl = k3 ^ bl
有(2):cl=0x58,ebx=0x631a3451,(1):cl=0x43
(1):ebx ^= byte_4121C0[cl]
后ebx=0x6d236444,
所以k3 = bl ^ cl = 0x44 ^ 0x58 = 0x1C 属于有效取值范围[0x00,0x0D]
-------
即 k0,k1,k2,k3 = k03 = [0x1d,0x11,0x12,0x1C]
nazAZ = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
k03_str = b"".join([nazAZ[CharIndex] for CharIndex in k03])
得到k03_str = "this"
-----------------------------------------
同理可以对其它三种情形进行逆推求k0,k1,k2,k3值,
但实际求值过程中都值超过了有效取值范围[0x00,0x0D],丢弃
所以只有k03_str = "this"一种情形
-----------------------------------------
综上所述得到注册码 "thisIsSerialNumber"
另一只IDAPython直接枚举的方式
def getk03str():
nazAZ = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
ebx = c_ulong(0)
cl = c_ubyte(0)
dl = c_ubyte(0)
kn = c_ubyte(0)
for k0 in xrange(0,0x3E):
for k1 in xrange(0,0x3E):
for k2 in xrange(0,0x3E):
for k3 in xrange(0,0x3E):
kn.value = ~k0
ebx.value = Dword(0x4121C0+4*kn.value)
ebx.value = ebx.value ^ 0xFFF
dl.value = k1 ^ ebx.value
ebx.value = ebx.value >> 8
ebx.value = ebx.value ^ Dword(0x4121C0+4*dl.value)
cl.value = k2 ^ ebx.value
ebx.value = ebx.value >> 8
ebx.value = ebx.value ^ Dword(0x4121C0+4*cl.value)
cl.value = k3 ^ ebx.value
ebx.value = ebx.value >> 8
ebx.value = ebx.value ^ Dword(0x4121C0+4*cl.value)
ebx.value = ~ebx.value
if ebx.value == 0x0A466EEEF:
return b"".join([nazAZ[k] for k in [k0,k1,k2,k3]])
像素扫描缺陷
由于色差的原因,比如我的系统背底色为浅绿0xB6DEBB,
就与产生致命色差导致无法查表识别输入的字符信息
当输入"thisIsSerialNumber"注册码时,在纯白系统背底下
第一字符的像素矩阵前五个像素色值为左列所示,
而我的浅绿系统背底会在第四个像素产生致命色差,
同理,对于非纯白背底的情形,个别浅色素会被错误识别为白背底而产生致命错误导致无法识别。
ffffff 00B6DEBB <---背景色:纯白 0xffffff,浅绿 0xB6DEBB
b6ffff 00586C5C
000066 00586C5C
db903a 00B6DEBB(致命色差)
ffffff 00B6DEBB
004011E5 3D BBDEB600 CMP EAX,0ffffff
004011E5 3D BBDEB600 CMP EAX,0B6DEBB 修改背景色