首页
社区
课程
招聘
[求助]程序被跟踪出注册码的原因是什么?
发表于: 2008-12-21 22:13 6026

[求助]程序被跟踪出注册码的原因是什么?

2008-12-21 22:13
6026
我是个新手,近来学习破解的时候。

发现有一些程序通过跟踪可以找出注册码,然而有些却不会。

请问这两类程序到底有什么区别啊?

以后在自己编写的程序中,如何防止注册码被跟踪出来呢?

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (20)
雪    币: 2067
活跃值: (82)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
2
if 注册码='87F3E75D'   这种的可以

注册码 转成整数 x
if (x+123h)*45678h = 87F3E75D   这种的不行
2008-12-21 22:22
0
雪    币: 27
活跃值: (127)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
3
不解其意啊,可以说详细些吗。
2008-12-21 23:08
0
雪    币: 2110
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
4
sessiondiy是说,如果是进行字符串比较,那必然会出现字符串的明文。

如果将字符串转换成某种类型,再进行值比较,就不会出现明文的字符串格式的注册码了。

PS.如果你是VB程序员,可能不好理解,需要先学一下C语言,特别是C语言中的基本数据类型,一定要搞清楚。因为VB是弱类型语言。
2008-12-22 00:35
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
这样的,所谓的明码比较,是因为你程序里有一副完整的加密程序,在加密用户名等信息后,生产KEY 的过程中,被可以在单步跟踪时捕获内存的每个字节的调试器显示出来
2008-12-22 00:42
0
雪    币: 2067
活跃值: (82)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
6
我认为LZ可能没有学过任何一种语言
若猜错的话...对不起啦
2008-12-22 01:27
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
我也是这样认为 ^_^
2008-12-22 01:31
0
雪    币: 82
活跃值: (10)
能力值: (RANK:210 )
在线值:
发帖
回帖
粉丝
8
能猥琐则无敌,算法简单直接F5,算法强可以暴,但是拿key解密文件内容,我是直接等人自爆的。
2008-12-22 06:02
0
雪    币: 27
活跃值: (127)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
9
太小看人了吧。

虽然我不是高手,但至少VB、Delphi、C等等也都是学过的
2008-12-22 10:45
0
雪    币: 27
活跃值: (127)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
10
感谢书呆彭的耐心解答,还是版主好啊。

看了你的解释我弄明白了,我的理解是:

如果设置一种算法,把用户输入的值经过计算之后再和注册码的计算结果相比较。

这样就可以避免在程序中出现注册码了,你是这样的意思吗?

如果是这样的话,我在想,新的问题又出来了:

正确注册码的计算结果总要找个地方保存起来,这样才可以和用户输入的值的计算结果进行比较。

万一这个保存注册码计算结果的地方被别人发现了,岂不是很危险。

怎么办?
2008-12-22 10:59
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
反过来问,如果碰到的软件是跟不出来明文的,只能爆破么?但是又想做内存注册机怎么做呢
2008-12-22 11:27
0
雪    币: 2368
活跃值: (81)
能力值: (RANK:300 )
在线值:
发帖
回帖
粉丝
12
你可以算一个字节,比较一个字节。就可以不用担心了。
也可以用户名向下走,注册号向上走。在中间看能不能相遇...

呵呵..很多...
2008-12-22 11:27
0
雪    币: 27
活跃值: (127)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
13
是不是我太笨啊,又没看懂。

请书呆彭帮我回答下第10层的问题吧。
2008-12-22 11:39
0
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
个人觉得,写出注册机还是比较难的,有些函数的逆函数比较难求啊,就算你知道它的函数了,也难写出求逆的函数。要想破解,只能爆破了。
2008-12-22 11:47
0
雪    币: 2368
活跃值: (81)
能力值: (RANK:300 )
在线值:
发帖
回帖
粉丝
15
我没有仔细看你的话...
你的意思是
temp1=f(user)
temp2=G(password)
if temp1==temp2 then success

需要保存 temp1 和 temp2 真个是明文出现有危险..
实际上无论什么状况,危险都是存在的。这样比 if password== f(user)then success 安全.

如果 f()和G()两个不可逆,就最好了...

不要点将...下次点将的话...我就要生气了...(后面引用黎叔的话)
2008-12-22 11:50
0
雪    币: 2110
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
16
上面说的是防止在内存中出现注册码的明文,所以要将字符串转换后再比较。

现在新的问题已经不是明文的问题,而防爆破的问题。

防爆破是个很复杂的问题,简单来说,如果你的验证过程只在一处进行比较,不管比较的是明文还是某种转换结果,那即使你的转换过程再复杂,因为只有一处比较,那么就可以在比较点轻松爆破。

举个例子,假设 some_value_type Encrypt(std::string sn)是一个对注册码进行处理的函数,不管这个函数有多么复杂,甚至采用高强度的加密算法,如果你的程序只是使用类似这样的判断逻辑:

if ( Encrypt( GetInputSn() ) == valid_value )
{
      // 验证通过
 }
else
{
      // 验证失败
}


这样的判断逻辑,编译后必然有一个条件分支。那么只要找到这个位置,别人不用去管正确的值或者注册码应该是什么就可以轻松爆破。

一种最简单的改进是多步验证,但实质是将一个爆破点变成多个爆破点,别人只要把整个判断逻辑搞清楚,还是可以轻松爆破的。

还有一点,就是将验证代码分散开来,而且不立即验证,而是当受保护的功能被使用之前进行验证,对于防止简单爆破也有一定效果。

关于防爆,常用的方法还有利用异常处理来改变程序流程。这方面我不是专家,不多说了。

防爆是个很有意义的话题,也是软件保护当中最基本的问题之一了。

你试试在论坛搜索“防爆”,看能不能得到什么信息。
2008-12-22 12:00
0
雪    币: 27
活跃值: (127)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
17
什么是点将,是说我总是呼叫书呆彭吗?

呵呵,不好意思啊,下次我知道了。

------------------------------------------------------

我的意思是:

temp1 = f(用户输入的值)
temp2 = f(正确注册码) // 这个需要事先保存在一个地方,用到的时候读取

if temp1 == temp2 then success

------------------------------------------------------

问题是:

如果保存temp2的位置被别人发现了,会很危险。

求解决的办法。

------------------------------------------------------

PS:这样比 if password== f(user)then success ,岂不是出现明文(password)了吗?
2008-12-22 12:14
0
雪    币: 2110
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
18
你这还是没理解为什么要先进行转换。

既然我们比较的是转换之后的值,那么正确的注册码的原文是不需要的,所以程序里只需要存储temp2的值,这个值根本就是一个const,而根本不用在运行时再计算temp2=f(正确注册码),所以程序里也不用存储正确的注册码的明文了。

如果这个值是一个简单数据类型,比如32位整数,那么我们甚至根本没必要定义一个const some_value_type temp2,只需要使用一个立即数即可。

而所谓“明文”,是指“正确注册码”,而不是temp2。

所以
if ( temp2 == f( 用户输入的字符串 ) ) then success 
这样的代码中,并不会出现明文。

最简单的,f可以是一个单向散列函数,那么别人是无论如何也不可能通过简单的跟踪就知道正确注册码是什么,所以只能爆破。

但如果不是与固定的序列号比较,而是需要与注册的用户名相关联,f必须是一个可逆的函数,此时temp2不再是const,但我们设计算法,可以从username计算得到temp2,而不从正确的注册码得到temp2。

再说一次,这里说的是防止明文出现的方法,而不是防止简单爆破的方法。防爆需要其它的技术。
2008-12-22 12:27
0
雪    币: 27
活跃值: (127)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
19
能给出一个多步验证的代码示范吗?

我以前写程序的经历里,都是一步判断的,越简单越好;

现在涉及到软件保护,反而是越复杂越好了。

所以暂时有点不适应,谁可以示范一下多步验证。
2008-12-22 12:34
0
雪    币: 2110
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
20
多步验证就是分多个步骤啊!

我曾经在一个CrackMe中看到过一种方法,很值得参考。具体是谁写的CrackMe记不住了。

大致是这么个过程(只是示例,具体应用请自己发挥):

// 先定义一个函数指针
typedef  bool (*function_t)(std::string const&);
function_t    next_step = &null_stub;

...

// 取得用户输入,开始验证,我还添加了个利用C++异常处理的“小伎俩”

std::string sn = GetUserInput();

next_step = &step_one;

try
{
  while( next_step( sn ) )
    ; // 空循环,实际工作在next_step的调用中,如果上一步成功,则调用下一步。
}
catch(  function_t last_step )
{
    if ( last_step(sn) )
        throw;
}

...

// 实际的验证步骤由以下的函数序列完成,可以自由发挥。

bool   null_stub(std::string const & )
{
    return false;
}

bool   step_one(std::string const & sn)
{
    // 对sn作第一步的验证,另外为干扰跟踪,可以添加垃圾代码等。
    // 我就以第一步验证字串长度为例
     if ( sn.length() < 8 )
        return false;
     if ( sn.length() > 17 )
     {
        next_step = &null_stub;
        return true;
     }
     if ( isdigit( sn[0] ) )
        return false;

     next_step = &step_two;
     return true;
}

// 以下是第2步,等等,自由发挥吧
bool step_two(std::string const& sn)
{
    if ( ... )
        throw &good_sn;
     else
        next_step = &bad_sn;
     return true;
}

// step_three,step_four,...
// good_sn,bad_sn,trial_sn,...
2008-12-22 13:01
0
雪    币: 27
活跃值: (127)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
21
终于问得我有“吃饱”的感觉了,谢谢大家参与到讨论中来。

尤其感谢书呆彭对我的问题进行这么耐心的解答。

谢谢你啊。
2008-12-22 13:18
0
游客
登录 | 注册 方可回帖
返回
//