破解某PDF转换器产品
本文章纯属出于作者自己对技术的探索,绝不用于商业用途(虽然网上已经能够下载到注册机了)
软件功能就不多说了,PDF转换成WORD格式,对于学生党来说也算是神器了吧,那么我们今天就用自己的办法来获得这款神器的使用权。
下图是注册界面,软件会给我们提供一个机器码,那么可以推测,注册码就是根据机器码加密而成的了。
很遗憾OD并不能对这款软件进行调试,还好我们有另一个神器———IDA,先分析一下.exe文件,函数比较多。。一时找不到下手点。那我们先尝试输入一个错误的注册码,弹出了一个提示框
点确定后自动连接了如下网址:
tj.sjhfrj.com/redirect/ver1/pdfconverter/buy/6.5/Setup_xjpdf2word/1797259983
我们可以从这个网址上下手,在IDA里浏览一下字符串,看到了几个关键字符串,我们可以选择任何一个来查看它的交叉引用。
然后我们定位到了registerCodeEnter()函数中来,其上层函数如下图,那么这个registerCodeEnter()十有八九就是我们点击注册之后进入的函数了。
在registerCodeEnter()函数中我们看到了一个字符串判断的函数,如果判断不相等则跳到含有字符串”tj.sjhfrj.com/redirect/ver1/pdfconverter/buy/6.5/Setup_xjpdf2word”的函数中,所以我们有理由怀疑这个判断所调用的两个字符串就是真注册码与我们所输入的注册码,get_text得到的当然是我们输入的注册码,那么在PDFConvert.bllBase.dll中的get_reg_code(string)函数就是生成注册码的关键函数了(它调用的参数是string类型,初步猜测是机器码,返回值也是String类型,应该就是注册码)。
让我们来分析PDFConvert.bllBase.dll
为了使加密算法更直观,我把对整个get_reg_code函数的分析提取了出来:
.method public hidebysig instance string get_reg_code([opt] string machine_code)
{ .param [1] = string("") .maxstack 3 .locals init (int64 V0, string V1, int32 V2) ldarg.1 ldsfld string [mscorlib]System.String::Empty call bool [mscorlib]System.String::op_Equality(string, string) brfalse.s loc_1025 ldarg.0 call instance string PDFConvert.bllBase.reg::get_machine_code() starg.s 1 // 得到机器码(string型)
loc_1025: ldarg.1 call int64 [mscorlib]System.Convert::ToInt64(string) stloc.0 // 把机器码转化成int64型的整数,保存到变量v0中 ldstr asc_20CE // "" stloc.1 ldc.i4.0 stloc.2 // 初始化一个int变量v2为0,作为计数器使用 br.s loc_1069 // 将计数器的值与0x64比较
loc_1036: ldloc.0 ldc.i4.2 conv.i8 mul // v0 = v0*2 stloc.0 ldloca.s 0 call instance string [mscorlib]System.Int64::ToString() stloc.1 // 把变量v0转化成字符串保存在v1中, ldloc.1 callvirt instance int32 [mscorlib]System.String::get_Length() ldc.i4.s 0xC // 获取v1长度与0xc比较 bgt.s loc_1056 ldloc.1 call int64 [mscorlib]System.Convert::ToInt64(string) stloc.0 br.s loc_1065
loc_1056: ldloc.1 ldc.i4.0 ldc.i4.s 0xC callvirt instance string [mscorlib]System.String::Substring(int32, int32) call int64 [mscorlib]System.Convert::ToInt64(string) stloc.0 // 如果v1长度大于0xc,则截取其前8位转换成int64型保存在v0中
loc_1065: // CODE XREF: PDFConvert.bllBase.reg__get_reg_code+44j ldloc.2 ldc.i4.1 add // v2++ stloc.2
loc_1069: ldloc.2 // 将计数器的值与0x64比较 ldc.i4.s 0x64 blt.s loc_1036 // 如果比0x64小,则进入循环 ldloca.s 0 call instance string [mscorlib]System.Int64::ToString() ret } |
然后我们需要尝试这用c++把源码还原出来,其中的大数操作真真的让人很头疼。
QWORD CtextDlg::encode(CString code) { QWORD m_code = 0; QWORD m_temp= 0; CString tmp; for (int i = 0; i < 0x64; i++) { tmp = code.Right(8); code = code.Left(code.GetLength() - 8); m_temp = _tcstoul(tmp, NULL, 10); m_code = _tcstoul(code, NULL, 10); m_code = m_code * 100000000 + m_temp; m_code *= 2; code.Format(L"%d", m_code / 100000000); code.AppendFormat(L"%08d", m_code % 100000000); int j = code.GetLength(); if (j>12) { code = code.Mid(0,12); } } tmp = code.Right(8); code = code.Left(code.GetLength() - 8); m_temp = _tcstoul(tmp, NULL, 10); m_code = _tcstoul(code, NULL, 10); m_code = m_code * 100000000 + m_temp; return m_code; } |
至此,注册机就算是出炉啦,让我们试一试效果
Perfect!可以开开心心的使用啦!