Stylizer 是一个比较好用的CSS设计工具,从官网拿到它的最新版本后,发现现存的破解都不可用,所以跟进分析了下它的内容。
在分析之前,看了一下现存的逻辑,都是通过使用破解过的Stylizer.Application.dll替换安装文件后,就可以正常使用了,但是最新的版本,软件安装完后很干净,就两个文件:Stylizer7.exe,uninstall.exe ,这样很明显新版本已经做了更多的保护,越是这样就有分析的欲望了。
先IDA里字符串查找, 并没有找到特别多的信息,复杂的先不深入。
使用x64dbg动态调试下,进行开发信息识别:
好像是用C++开发,所以打算通过CE来定位注册逻辑进行分析,字符查找的时候,确认使用的是UTF-16的。定位到输入的无效Key地址有四个:
使用内存读取断点以后,进行“Authorize",进行调试,断下来,但是发现响应的代码并不在.text段:
000007FE990A0000 0000000000069000 PRV ERW------
这个就有点奇怪了,但是查壳并没有壳信息,所以从这个点回溯去了解启动阶段,从x64dbg进行调试
发现会在函数13FD32E37 Call 13D31230() 触发异常,从IDA中定位去看这个函数:
_int64 __fastcall sub_140001230(void *Src, __int64 a2, wchar_t *a3) { CLRCreateInstance ICLRMetaHost::EnumerateInstalledRuntimes ICLRRuntimeInfo::GetInterface ICorRuntimeHost::GetDefaultDomain ... }
从函数中的提示信息,可以看到基本的操作过程,简化如上给出的信息。这个有点奇怪,对这个API不熟悉,所以查找了下相关的内容.
比较有用的信息是这个参考:https://www.experts-exchange.com/questions/28909682/C-Loading-Managed-Assembly-From-Memory-in-Unmanaged-Process.html
简单来说,上面的这些API是进行.net的运行时初始化和加载的操作,通过这个方式,可以实现C++ 运行时加载C#开发的APP。
这个就比较有意思了,运行程序没有壳,但是运行的代码在内存其它段中,有可能这个也是使用C++开发的加载器,实现的C#程序是动态加载的,那么这样的话,C#程序在哪儿呢?
查找sub_140001230后,判断应该是在下面的这个阶段能得到C#完整文件信息:
SafeArrayLock(v23); v24 = v23->pvData; memcpy_s(v23->pvData, v22, v4, v22); // 可能不是文件,而是打包好的执行程序数据。在这里进行缓冲区写入??? // memcpy_s(void *dest, size_t destSize, const void *src, size_t count); ++v24[134]; v25 = v77;
在x64dbg中设计断点,执行到这儿后,获取到v4的值和V22信息:
000000013F8F1683 | 8BD6 | mov edx,esi | ; DstSize = 0x62A400 000000013F8F1685 | 44:8BCE | mov r9d,esi | ; MaxCount = 0x62A400 000000013F8F1688 | 4D:8BC7 | mov r8,r15 | ; Src = 0x2300040 000000013F8F168B | 48:8BCB | mov rcx,rbx | ; Dst = 0x1B5A0040 000000013F8F168E | E8 D1F30E00 | call stylizer7.13F9E0A64 | memcpy_s(v23->pvData, v22, v4, v22);
在内存中转到地址 0x2300040,看到到PE文件特征:
0000000002300040 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 MZ..........ÿÿ.. 0000000002300050 B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ¸.......@....... 0000000002300060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0000000002300070 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 ................ 0000000002300080 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 ..º..´.Í!¸.LÍ!Th 0000000002300090 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F is program canno 00000000023000A0 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 t be run in DOS 00000000023000B0 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 mode....$....... 00000000023000C0 50 45 00 00 4C 01 02 00 FE 40 8F 5B 00 00 00 00 PE..L...þ@.[.... 00000000023000D0 00 00 00 00 E0 00 02 01 0B 01 08 00 00 9E 62 00 ....à.........b.
在x64dbg中使用命令 savedata :memdump:, 0x2300040, 0x62A400 进行内存区域DUMP。
在目录...release\x64\memdumps\memdump_37c8_0000000002300040_62a400.bin获取到导出文件,根据分析它应该是一个C#文件,使用dnspy加载。
从结果看,前面的分析都是正确的,而且DUMP出来的文件的资源中,引用了:Stylizer.Application.dll文件。(终于找到它了),在dnspy进行工程导出,在目录中得到了 Stylizer.Application.dll。
从之前的信息,关键的信息应该是在这个文件中,同样使用dnspy进行加载:
从这个结果看,这个文件是做了混淆保护的,这个时候,我好奇之前的补丁是怎么破解的,所以把之前的破解的这次的文件通过dnspy导出成工程后,进行文件对比, 不比不知道,发现这个软件混淆文件名都是确定的:
这样找到破解点应该就比较清楚了。 这样整体分析过程就分析清楚了。
并没有去分析Stylizer.Application.dll,从文件比较,可以确定patch点应该是此处:
1, 需要patch新的DLL文件;
2, 怎么修改Sytlizer7.exe文件;
对于问题1,因为使用了混淆,用dnspy是不行的,需要使用.Net Reflector作字节码编辑。
对于问题2,需要去回溯看看C#文件是的源是哪儿;
在IDA中回溯内存DUMP时的地址,发现是函数(unsigned int)sub_1400028B0(&v18, &Src, v9)处理的;进一步分析:
result = FindResourceW(a3, (LPCWSTR)0x6E, (LPCWSTR)2);// 查询 ID:110的资源,2:RT_BITMAP v7 = result; if ( result ) { result = (HRSRC)LoadResource(v3, result); // 加载ID:110资源 v8 = result; if ( result ) { v9_dwResourceSize = SizeofResource(v3, v7);// 获取资源大小 v10_ResBuffer = (char *)LockResource(v8); // 锁定内存中的资源数据块,它的返回值也就是我们要使用的直系指向资源数据的内存指针 v11 = *(unsigned int *)(v10_ResBuffer + 2);// 跳过"BM"后的值:DE 06 00 00 = 0x06DE = 1758 v12_TmpEntry = &v10_ResBuffer[v11]; // 在内存缓冲中位置ResBuffer[1758] v13_TmpSize = v9_dwResourceSize - v11; VirtualProtect(&v10_ResBuffer[v11], 4ui64, 4u, (PDWORD)&uBytes + 1);// 调整内存区域的属性。 *(_DWORD *)v12_TmpEntry = 0x4643534D; VirtualProtect(v12_TmpEntry, 4ui64, HIDWORD(uBytes), (PDWORD)&uBytes + 1); if ( (unsigned int)sub_1400026B0((__int64)v12_TmpEntry, v13_TmpSize, 0i64, (int *)&uBytes) ) return 0i64; v14 = LocalAlloc(0, (unsigned int)uBytes);// Allocates the specified number of bytes from the heap. if ( (unsigned int)sub_1400026B0((__int64)v12_TmpEntry, v13_TmpSize, (__int64)v14, (int *)&uBytes) )// 抽取数据到分配的内存中
从上面的信息基本可以看出,应该是把C#文件打包成CAB包后,放置在一个BMP的资源对象中了。
到此分析整理如下:
Stylizer7.exe +-Resource : Bitmap:110 (size:0x279F18) +-cab文件(Bitmap:0x6DE - end ) // cab文件 +-S文件(解压cab文件size:0x62A400) +-Stylizer.Application.dll(Fileoffset:0x003E1EF6, size:0x18BA00) +-进行Stylizer.Application.dll Crack.
1,resourcehacker :提取bitmap文件为:Bitmap110.bin
2,使用010editor ,选择[begin:0x6DEh, size:0x27983Ah], 并保存选择部分内容为:Bitmap110_6DEh_27983Ah.bin
3,正常的cab文件开送4字节为:MSCF ,修改Bitmap110_6DEh_27983Ah.bin文件前四字节为:4D 53 43 46
4,使用winrar提取cab包内的文件S
5,再次使用010editor打开s,提取(begin:0x003E1EF6, size:0x18BA00h),获取文件:Stylizer.Application.dll
6,使用dnspy加载Stylizer.Application.dll文件,进行分析,破解;
还是自己对Windows上的开发不熟悉,之前只看了patch文件,并没有安装测试,在实际整理的时候,发现之前的版本的安装文件也符合上面的分析过程,但是Patch方式比较有意思,它利用了系统加载DLL的优先级,在执行文件的目录放置DLL之后,系统会选择加载被patch过的DLL,来实现破解!!!所以破解就方式就比较清楚了(作为补充信息整理提供),另外,其实有了这个方法,对DLL的调试也变的轻松可行,通过Dnspy将exe文件和DLL同时加载便可以直接调试。
> Stylizer.Application.dll!UfZfjfJNiaIQHBaGVTFHdvyYQJZS.vmlsjNgJZFueobzSWqrrLTtoleJ.get() (IL=0x0000, Native=0x000007FE99A153A0+0x18) Stylizer.Application.dll!UfZfjfJNiaIQHBaGVTFHdvyYQJZS.KianvyyqNFMOpNQpuTsMzACyWNk(short A_0, string A_1) (IL=0x0134, Native=0x000007FE99A01260+0x343) Stylizer.Application.dll!OlTWSKLXIZGjErEXkqKwyHbVUGJ.KianvyyqNFMOpNQpuTsMzACyWNk() (IL=0x0014, Native=0x000007FE99A006C0+0x49) Stylizer.Application.dll!Skybound.Stylizer.UI.StylizerApplication.OnEventLoopStarting() (IL=0x0005, Native=0x000007FE99A005F0+0x2B) Skybound.XApp!Skybound.XApp.DocumentModel.XApplication.<Run>b__0() (IL=0x0006, Native=0x000007FE99A00480+0x45) Skybound.XApp.Win32Library!Skybound.XApp.Win32.Win32EventLoop.<>c__DisplayClass2.<EnterEventLoop>b__0(object param0, System.EventArgs param1) (IL=0x0016, Native=0x000007FE99936A00+0x55) System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.System.Windows.Forms.UnsafeNativeMethods.IMsoComponent.FDoIdle(int grfidlef) (IL=0x001D, Native=0x000007FE99936610+0x7A) System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(System.IntPtr dwComponentID, int reason, int pvLoopData) (IL=0x01CF, Native=0x000007FE99932AE0+0x632) System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason, System.Windows.Forms.ApplicationContext context) (IL=0x01FA, Native=0x000007FE9992F7B0+0x620) System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) (IL=0x001C, Native=0x000007FE9992F6D0+0x6D) System.Windows.Forms.dll!System.Windows.Forms.Application.Run() (IL=0x0010, Native=0x000007FE9992F4D0+0x5B) Skybound.XApp.Win32Library!Skybound.XApp.Win32.Win32EventLoop.EnterEventLoop(System.Action onEntered) (IL=0x0065, Native=0x000007FE9992DF40+0x163) Skybound.XApp!Skybound.XApp.XEventLoop.StartEventLoop(System.Action onStarted) (IL=0x0077, Native=0x000007FE9992D9F0+0x215) Skybound.XApp!Skybound.XApp.DocumentModel.XApplication.Run() (IL=0x0026, Native=0x000007FE999226F0+0x97) Skybound.XApp!Skybound.XApp.DocumentModel.XApplication.Run(Skybound.XApp.DocumentModel.XApplication instance) (IL=0x0029, Native=0x000007FE999225C0+0xAC) Stylizer.Application.dll!Skybound.Stylizer.Program.Main(System.Func<Skybound.Stylizer.UI.StylizerApplication> createApplication, params string[] args) (IL=0x0010, Native=0x000007FE9911B8D0+0x7B) Stylizer7!Skybound.Stylizer.Win32.Win32Program.Main() (IL=0x0028, Native=0x000007FE99119620+0x9B) [本机到托管的转换] mscorlib.dll!System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(object obj, object[] parameters, object[] arguments) (IL=0x000F, Native=0x000007FE99108DC0+0x80) mscorlib.dll!System.Reflection.RuntimeMethodInfo.Invoke(object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, object[] parameters, System.Globalization.CultureInfo culture) (IL=0x007F, Native=0x000007FE991079F0+0x1DD) [本机到托管的转换]
之前对C#的调试,Patch不熟悉,这样整体过了一次。
到止完结了,还是没有现成的。~V~
最后于 5小时前 被nevinhappy编辑 ,原因: