从未公开过的方法:软件防爆破之绝招
http://www.cnsw.org/bbs/viewthread.php?tid=2056
从未公开过的方法:软件防爆破之绝招
假设A为验证代码段,爆破一般为找到A代码段中某处然后修改,可以这样做:
取随机数X为 1 或者 2
if X=1 then
再次取随机数X为 1 或者 2
if X=1 then
再次取随机数X为 1 或者 2
if X=1 then
插入代码A
else
插入代码A
end if
else
再次取随机数X为 1 或者 2
if X=1 then
插入代码A
else
插入代码A
end if
end if
else
再次取随机数X为 1 或者 2
if X=1 then
再次取随机数X为 1 或者 2
if X=1 then
插入代码A
else
插入代码A
end if
else
再次取随机数X为 1 或者 2
if X=1 then
插入代码A
else
插入代码A
end if
end if
end if
目的:由于取了随机数,破解者每次调试找到的代码A都不是同一处,很难全部Path8处代码A,甚至可以再多写一层随机,那就是16处。
最后说一下,这个方法是否有效我也不晓得,请哪位熟悉破解的朋友看过以后评价一下是否有效~~
种方法是有效的,但是要注意代码A本身的变形,所以重点是:
代码A本身的变形 + 随机调用变形后的代码A
我曾经使用过,对于防止PATCH类的爆破是非常有效的。
因为我们知道,很多所谓的CRACKER都是连CRACKER本身的职业道德都缺乏,往往是拿过软件,修改几下,看起来正常就去发布了,根本不会仔细认真地测试,向上面的那种随机陷阱是可以用来让这些CRACKER出丑用的,呵呵,当然,同时再加上不定期的随机验证,可以让这个CRACKER在以后的日子里不再轻易发布你的软件的爆破产品--为什么?因为经常出丑,会害得他在解密圈里名声很臭,呵呵。。。。。
防爆破法术一则
http://www.cnsw.org/bbs/viewthread.php?tid=2088
设A为验证代码段
判断计算机cpu序列号(反正计算机唯一标示,随便取个什么),取其中一位赋值 X
select case X
case 0
A
case 1
A
case 2
A
......
case 9
A
end select
这样就ok啦,出来的爆破有十分之九的计算机上是不能用的~~
不使用CRC进行exe自校验的编程办法(转帖)
原文: http://skyfire.dns0755.net/newweb/list.asp?id=201
可执行文件的自身检测
nowcan.yeah.net 2003-9-1 老侃第一站
当我们完成一个工程,编译成可执行文件后,一般是不希望这个可执行文件被人改动的,那么这里就讲述一下这是如何做到的。
其实这并不难,只要一个API函数就可以完成,这就是MapFileAndCheckSum。这个函数的作用是1)映象文件,2)从映象文件中接受原始的校验和,它是在编译时有编译器写入文件的,3)计算文件的校验和。如果文件在编译后被改动,那么原始的校验和就会和计算得出的校验和不同,由此可知文件被改动。下面的程序中,HeadChksum是原始的校验和,Chksum是计算得出的校验和,最后比较他们是否相同来判断文件是否被改动。
程序是BCB5写的,要加上imagehlp.lib这个库,并且Project->Options->Advance Linker中要选中Calculate Checksum。这样编译器才会计算校验和并写入文件。例子程序在这里。
在VC6里又有不同,同样要连上imagehlp.lib这个库,然后在Project->Settings->Link中去掉Generate debug info和Link incrementlly选项,再选择Category组合框的Customize,去掉Use program database选项,最后在Project Options中加入"/release",一切OK!
//---------------------------------------------------------------------------
#pragma hdrstop
#include
#include
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
DWORD HeadChksum=1,Chksum=0;
char Fn[512];
GetModuleFileName(GetModuleHandle(NULL),Fn,512);
if(MapFileAndCheckSum(Fn,&HeadChksum,&Chksum)!=CHECKSUM_SUCCESS)
{
MessageBox(NULL,"Check error!","Error",MB_OK);
}
else
{
if(HeadChksum!=Chksum)
MessageBox(NULL,"File changed.","Warning",MB_OK);
}
return 0;
}
//---------------------------------------------------------------------------
但是如果用了VCL,编译时居然说有冲突,主要是Imagehlp.h这个头文件的问题。我想最简单的解决方法是动态调用这个函数,LoadLibrary/GetProcAddress/FreeLibrary等,相信大家都会的,我就不写代码了。
防破解问答集(zt) http://www.cnsw.org/bbs/viewthread.php?tid=1429 当发现自己为之工作了好几个月,甚至几年的程序被人破解的时候,所受的伤害是难以形容 不要问我问题,我可能无法回答: 不要用有意义的文件名比如License.Dat.。 用类似Asymetric(美国软件公司,代表软件Toolbook)的加密. 仅仅不寻常的文件名常常 加上长时间延迟,当发现被自身被损坏时,不要发出警告,随后开始等待,也许是一或两天 加入短暂延迟,当输入口令或做其它检测时,停一到两秒钟,使穷举无法继续。简单易行, 使用相互检查,在DLL和EXE中互相检查,这远谈不上安全,但可以使破解变得更困难。 在软件中使用自我修复,你知道就像纠错Modem和容错硬盘,这技术已经有许多年了,怎么 修补你的软件!把代码变为每次调用不同的确认程序段,用“其人之道还治其人之身”。 把序列号放在不寻常的地方,比如数据库字段的属性中,经常听到或读到,“用一个DLL的 把序列号放到不同的地方。 不要依靠系统时间,从一些文件取得时间,比如SYSTEM.DAT,SYSTEM.DA0和BOOTLOG.TXT, 不要用明文字符串告诉用户:"对不起,不过...(或类似的东西)"这些是首先寻找的目标, 用伪造的程序调用和字符串来灌水。 不要使用一个确认函数,每次你确认用户,把确认代码写在当前过程中。这样只是让破解者 使用“保留字”,当使用硬密钥或口令时,使它们看来像程序代码或者函数调用 (比如., " 没有“禁止”特征,如果你的程序有不保存数据版本(Crapware Version),不要包含“灰” 避免不必要的提示信息,唯一提醒用户他尚未注册的只是“关于”对话盒,此对话盒要动态 经常更新,频繁的更新指:经常更换代码,典型(简单)的破解只修改你的硬字节代码位置 最后,花点时间考虑保护你自己的软件。它是否值得保护?它是否更应该改进你的软件?如 -------------------------------------------------------------------------------- 小心运行时刻库!当写BETA版时,完全使用之,在正式版中重写部分函数,这至少可以使破 毁坏结果,毁坏结果有时是保护程序的有效措施。 陷阱,一个我不太肯定,但听说有程序使用的方法:用CRC校验你的EXE文件,如果它被改变 不要依赖EXE压缩程序,几乎任何EXE压缩程序(Shrinker, WWPack32, NeoLite ——和所有 到处贴条件转移 使用部分代码作为奇妙的数字表。 和破解者斗智 提早发现SoftIce.。 这部分中真正有趣的是:例程(被用来响应用户界面的窗体的元素)的地址是按名字邦定的 object RegButton: TButton 这是什么?这是带有“注册”标题的按钮。你可以看到它的大小,位置......和一个有启发 000A4990 ____ ____ ____ BC57 4A00 0E52 6567 4275 ______.WJ..RegBu 000A49A0 7474 6F6E 436C 6963 6B__ ____ ____ ____ ttonClick_______ 现在,观察名字(Name)前那写神奇的数字,有一个字节('0E')指出了"RegButtonClick" 有的反汇编程序会以为文件太长,并且不能正确反汇编这部分——然而,使用特殊的工具, 0044ECC8 55 push ebp 如何避免被类似的程序破解? RegButton.OnClick := RegButtonClick; 当然你需要在窗体建立时(被调用前)执行这段代码,最好是被一些无关的例程所调用,当 -------------------------------------------------------------------------------- 只是些想法 Richey 摘自《hubdog未经证实的葵花宝典 返回: ElGamal算法既能用于数据加密也能用于数字签名,其安全性依赖于计算有限域上离散对数这一难题。 a = g^k ( mod p ) M = xa + kb ( mod p - 1 ) 签名就是( a, b )。随机数k须丢弃。 y^a * a^b ( mod p ) = g^M ( mod p ) 同时一定要检验是否满足1<= a < p。否则签名容易伪造。 a = g^k ( mod p ) ( a, b )为密文,是明文的两倍长。解密时计算 M = b / a^x ( mod p ) ElGamal签名的安全性依赖于乘法群(IFp)* 上的离散对数计算。素数p必须足够大,且p-1至 美国的DSS(Digital Signature Standard)的DSA(Digital Signature Algorithm)算法是经E |
如何用简单方法防止破解
http://www.cnsw.org/bbs/viewthread.php?tid=1063
在Debug的手册里可以看到Debug工具的局限. 第一个局限是只能下4个内存区域的断点,每个断点不能控制超过两个字节,这样内存断点不能控制超过16个字节的区域. 第二个局限是对多线程只能同时跟踪一个线程.
假设你的注册部分有300行,你可以分成30个inline函数调用或MACRO(一定要inline),func1(),func2()... func30(). 将他们随意放到程序的各个部分,一定不能放在一起(自己能找到就行了)。不要用Memcpy等常用系统调用拷贝注册码,近可能自己写,像Memcpy很好写,性能差点无所谓。经过编译后inline函数展开,注册部分和其他代码混在一起,他要写出注册机就像大海里捞针,在几十万甚至上百万汇编代码里找出有用的注册部分。
利用Debug的第一个局限最重要的一点是:注册码也不要放在一起,假设你的注册码是12位,千万不要用一个12位的数组放注册码,你可以在程序的不同位置定义12个全局字符变量,每个放一位,这样注册码在内存就不连续了。最好再加密处理一下(简单的字符异或就可以),验证时再解密。也不要用连续内存保存验证用到的变量,尽量将用到的验证临时变量分散定义在程序的不同处,再在验证中,不断转移一些值到其他变量中,对付暴力和Loader会比较有效。
没有必要用复杂的加密算法,更容易成为追踪的目标。只要你将注册部分隐藏的足够好,也没有漏洞,你花1天写的加密算法,破解者可能会花100-1000倍的时间破解。大部分人都会放弃。
你将注册做在一起,就像将你的财宝放在现代保险箱里,虽然非常坚固难以解密,对于开锁高手两分钟就打开了。
而古代海盗用的方法是将财宝埋在海岛上,这样没有藏宝图,对应高手和低手都只有一条路,拿一把铁撬挖,可能要挖一生。程序有那么多代码,反编译出来可能超过百万行,你将注册部分藏在里面,藏的好就如同将财宝埋在海岛里。那些所谓的Crackme只是给高手玩儿的现代保险箱而已,用原始的方法可以达到同样效果。
1. 读完注册码后不要立刻检查注册码,因为读注册码肯定用到系统调用,系统调用附近很容易下断点。先放到内存作为全局变量,然后你可以在程序的任何部分,任何时候,读注册码,读内存是没有任何系统调用的.
2. 两种办法处理在内存的注册码,
一种方法是在检查前分散隐藏注册码,这样他们无法从内存中搜索到注册码出现的位置,因为他们会在注册码出现位置附近下断点。
还有一种方法是正好相反,你可以在读到注册码后,多次将注册码在内存(用Malloc分配多处)的各个位置做大量拷贝,这最多浪费一些内存。16Bits的注册码做10000份拷贝也只用160K内存。如果不用Malloc分配这些内存,那么最好和其他程序使用的全局变量交互混在一起(这样即使破解者用HEX 编辑器打开并搜索你的程序中使用那部分内存的代码,也无法将正常程序数据和注册码区分出来). 你不要立刻检查注册码,10000份拷贝你只要以后随机找一份用就行了,破解的人不知道你正在用的是那一个. 同时你可以不断生成一些假的读取内存注册码的调用干扰破解者。这种方法对程序的性能影响微不足到,只是浪费一点内存。因为Debug对内存下断点的局限,这种情况他要下断点,累死的就是破解的人了.
3. 程序多处做CRC校验文件大小检查,发现不对就退出。一定要多处检查,不能只检查一次。
4. 用inline函数将注册部分分成许多小块,分散到程序各处运行。最好能放在不同的线程中运行. 检查结束不要给任何提示,在程序中的内存中做一个标志即可,提示信息要延迟一段时间出现,不要让破解者通过提示信息找到标志位置或检查结束位置,否则前功尽弃。当然也可以象上面那样做10000个标记,随机用一个,这时你不用担心破解者知道标记的位置.而且标记最好不要用0或1,可以用一个貌似随机的值作为注册成功的标记,如何产生这个随即值只有你自己知道.
什么算法无所谓,最终目的就是让破解者的作用发挥不出来。和古代海岛藏宝一样,你只要把检查痕迹很好擦掉分散,破解高手的用处就发挥不出来。破解者玩的Crackme就是保险箱,如果是开锁高手,目标明确总能打开,不行还可以用炸药。但到海盗的藏宝地点,任何开锁高手都没有用。
这种方法用的好的结果是你容易创造检查注册码的方法,自我创造发挥的余地很大,而对破解者会很麻烦,他搞不清楚你在干什么,你只要让破解者感觉象是蒙着眼睛走迷宫或者在猜没有谜题的谜语就行了. 而且对你来说更换算法也很容易,因为可能根本没有算法,只有谜语和迷宫。要充分利用程序反汇编后代码多这个特点,除了读注册码的时刻,其他时候根本没有系统调用,除了内存,根本无处下断点. 而你使用复杂的加密算法通常的结果是你麻烦,破解者很容易,因为各种加密算法都已经研究透了,而且用复杂的加密算法的调用或系统调用立刻暴露你检查注册码的位置,为暴力破解提供了方便。
我和很多人一样,也是不会汇编语言,而且程序一出来就被0day破解,而且几乎每一个版本它们都要破解. 苦于不会汇编,也不太了解破解流程,只好去看SOFTICE的手册,想了这么一个简单的方法. 0day虽然它们经验丰富也能破解,而且似乎也逐渐了解和改进对我的程序的破解. 但许多破解是坏的,根本不能用. 而且就是被破解后,只要将这些inline调用和全局内存变量的位置稍微变一变(大概只需要2-3个小时),它们下一次的破解又是坏的. 而且我还没有完全使用上面的方法,例如我还没有做10000份的内存拷贝或10000份的标记. 因为只是简单的用inline和将注册信息与其他全局变量混在一起,现在就已经够了,0day的暴力破解就经常会破坏正常程序数据.