首页
社区
课程
招聘
[分享]ECC替换公钥实践(上篇)
发表于: 2014-9-12 17:06 28490

[分享]ECC替换公钥实践(上篇)

2014-9-12 17:06
28490

下篇:http://bbs.pediy.com/showthread.php?t=192245

这段时间花了点时间研究了下怎么替换ECC公钥(v9.2 ~ v11.11.1.1),在这里与感兴趣的朋友分享下。

==================================
生成用自定义公钥、私钥的keygen
==================================
要生成120位SIGN2的ECC license,只要在lm_code.h里加上
#define LM_SIGN_LEVEL LM_SIGN2
#define LM_STRENGTH LM_STRENGTH_239BIT
然后选定一组LM_SEED1,2,3(可以由lmrand1 -seed产生,这里我用的下面这组数),然后编译SDK就可以了。
#define LM_SEED1 0x11111111
#define LM_SEED2 0x22222222
#define LM_SEED3 0x33333333

作为参考,产生的lmcrypt.exe, testlmd.exe见附件,这里选用的是9.2版的SDK,因为有源码,讲解和调试起来都比较方便。

========================================
lmnewgen可以产生lmpubkey.h和lmprikey.h
========================================
请注意下lmprikey.h里的内容,后面会用到
static unsigned char lm_pubkey[2][3][40] = {{{0x77, 0x9c, 0x40, 0xa, 0x58, 0xe2, 0x7c, 0xef, 0xc3, 0xed, 0x93, 0x71, 0x20, 0xe0, 0x97, 0x36},
  {0x76, 0xa1, 0xdd, 0x41, 0x32, 0x8c, 0x52, 0xb9, 0x2b, 0x9d, 0x5b, 0x68, 0xbf, 0x37, 0xbe, 0xa5, 0x82, 0x3f, 0x76, 0xca, 0x92, 0xd2},
  {0x76, 0x9d, 0xe2, 0xab, 0x3b, 0x42, 0xd7, 0x6b, 0x20, 0xb5, 0x46, 0x39, 0xed, 0xbc, 0xa0, 0xd1, 0xcb, 0xb, 0x5d, 0x65, 0xdc, 0xe5, 0x39, 0x63, 0x44, 0x80, 0xcd, 0x78, 0x27, 0x8c, 0x17}}
,
  {{0x77, 0x9b, 0x2f, 0xbb, 0x1f, 0x8, 0x7c, 0x42, 0x93, 0xb6, 0xcb, 0x1, 0x4c, 0x68, 0x8d, 0xb0},
  {0x76, 0x9f, 0xeb, 0xa9, 0x94, 0x3d, 0x5a, 0xba, 0xc, 0x97, 0x1, 0x4a, 0xc8, 0xc2, 0x9f, 0x43, 0xdc, 0xe4, 0xd1, 0x5, 0xf9, 0x84},
  {0x76, 0x9e, 0x6a, 0x55, 0xc2, 0x34, 0xfd, 0x24, 0xf, 0x95, 0xd1, 0x29, 0xbb, 0xf9, 0x1, 0x85, 0x1, 0x3a, 0x53, 0x17, 0x2a, 0x98, 0xbf, 0xb3, 0x62, 0x76, 0xec, 0x9a, 0x87, 0x69, 0x53}}
};
    
static unsigned int lm_pubsize[2][3] = {{0x10, 0x16, 0x1f}
,
  {0x10, 0x16, 0x1f}
};

==============================================================================
1.我们先从获取public key开始(这里以testlmd为例,对实际应用,方法是一样的)
==============================================================================
打开SDK里src\l_prikey.c可以看到下面这段,那么第二个参数(&m->publicKey)存放的就应该是public key了。  

if ((returnValue = sb_ecdsaVerifyEnd( m->global_data, &m->publicKey,
     &ecc_sig, &verifyContext, &verificationResult)) != SB_SUCCESS) 
  {
    l_pubkey_err(job, 10544, returnValue);
    ret = LM_PUBKEY_ERR;
    goto exit_verify;
  }

OD里找到对应的位置下断,
.text:0041D5A9 loc_41D5A9:                             ; CODE XREF: _l_pubkey_verify+7A6j
.text:0041D5A9                                         ; _l_pubkey_verify+7D6j
.text:0041D5A9                 lea     edx, [ebp+verificationResult]
.text:0041D5AC                 push    edx
.text:0041D5AD                 lea     eax, [ebp+verifyContext]
.text:0041D5B3                 push    eax
.text:0041D5B4                 lea     ecx, [ebp+ecc_sig]
.text:0041D5BA                 push    ecx
.text:0041D5BB                 mov     edx, [ebp+m]
.text:0041D5C1                 add     edx, 44h
.text:0041D5C4                 push    edx        <= check edx, will get the public key
.text:0041D5C5                 mov     eax, [ebp+m]
.text:0041D5CB                 mov     ecx, [eax+4]
.text:0041D5CE                 push    ecx
.text:0041D5CF                 call    _sb_ecdsaVerifyEnd

查看0041D5C4处,edx里对应的就是public key

02 02 6F DF CF AF 73 DF BB C6 D2 A5 80 20 2C B4 58 7F F1 D2 78 91 D4 D6 D0 EC 60 1C B3 F1 A4



==================================
2.看看公钥在文件里是怎么存储的
==================================

函数_sb_ecdsaVerifyEnd是被_l_pubkey_verify调用的,好,我们回到函数l_pubkey_verify的起始点开始追踪[00C93B3C~00C93B5E]处是怎么变成public key的。

run过0041D143后,这块内存区域清零

0041D143  |.  E8 E82A0100   CALL testlmd.l_malloc                    ; \l_malloc



在此处下内存写断点,如下图所示,



一路F9很容易来到0041D273处,再来看下内存中的这段数字:

76 9D E2 AB 3B 42 D7 6B 20 B5 46 39 ED BC A0 D1 CB 0B 5D 65 DC E5 39 63 44 80 CD 78 27 8C 17



回头再看下lmpubkey.h里的内容,有点明白了吧?

static unsigned char lm_pubkey[2][3][40] = {{{0x77, 0x9c, 0x40, 0xa, 0x58, 0xe2, 0x7c, 0xef, 0xc3, 0xed, 0x93, 0x71, 0x20, 0xe0, 0x97, 0x36},
  {0x76, 0xa1, 0xdd, 0x41, 0x32, 0x8c, 0x52, 0xb9, 0x2b, 0x9d, 0x5b, 0x68, 0xbf, 0x37, 0xbe, 0xa5, 0x82, 0x3f, 0x76, 0xca, 0x92, 0xd2},
  {0x76, 0x9d, 0xe2, 0xab, 0x3b, 0x42, 0xd7, 0x6b, 0x20, 0xb5, 0x46, 0x39, 0xed, 0xbc, 0xa0, 0xd1, 0xcb, 0xb, 0x5d, 0x65, 0xdc, 0xe5, 0x39, 0x63, 0x44, 0x80, 0xcd, 0x78, 0x27, 0x8c, 0x17}}
,
  {{0x77, 0x9b, 0x2f, 0xbb, 0x1f, 0x8, 0x7c, 0x42, 0x93, 0xb6, 0xcb, 0x1, 0x4c, 0x68, 0x8d, 0xb0},
  {0x76, 0x9f, 0xeb, 0xa9, 0x94, 0x3d, 0x5a, 0xba, 0xc, 0x97, 0x1, 0x4a, 0xc8, 0xc2, 0x9f, 0x43, 0xdc, 0xe4, 0xd1, 0x5, 0xf9, 0x84},
  {0x76, 0x9e, 0x6a, 0x55, 0xc2, 0x34, 0xfd, 0x24, 0xf, 0x95, 0xd1, 0x29, 0xbb, 0xf9, 0x1, 0x85, 0x1, 0x3a, 0x53, 0x17, 0x2a, 0x98, 0xbf, 0xb3, 0x62, 0x76, 0xec, 0x9a, 0x87, 0x69, 0x53}}
};
    
static unsigned int lm_pubsize[2][3] = {{0x10, 0x16, 0x1f}
,
  {0x10, 0x16, 0x1f}
};

好,让我们从0041D273处往回看看这串数字是怎么转换成最终的public key的。

0041D252  |.  0FBE08        |MOVSX ECX,BYTE PTR DS:[EAX]

这里的ECX里的内容是什么:testlmd (daemon name, 对应ASCII码74 65 73 74 6C 6D 64

)

再往下

0041D261  |.  0FB642 48     |MOVZX EAX,BYTE PTR DS:[EDX+48]

EAX里就是上面lmpubkey.h里的第一位数字"76",

0041D265  |.  2BC1          |SUB EAX,ECX
76h- 74h = 02



继续一路下去,
76 9D E2 AB 3B 42 D7 6B 20 B5 46 39 ED BC A0 D1 CB 0B 5D 65 DC E5 39 63 44 80 CD 78 27 8C 17  (lmpubkey.h里的public key)
=>
02 02 6F DF CF AF 73 DF BB C6 D2 A5 80 20 2C B4 58 7F F1 D2 78 91 D4 D6 D0 EC 60 1C B3 F1 A4  (真正的public key)

我们用IDA的F5反汇编可以看到这段转换对应的伪代码

          for ( Gi = 0; Gi < pubkeysize[(_DWORD)offset]; ++Gi )
          {
            if ( !*cp )
              cp = job->vendor;
            if ( Gi % 2 )
            {
              if ( Gi % 3 )
                m[Gi + 72] += *cp++;
              else
                m[Gi + 72] ^= *cp++;
            }
            else
            {
              m[Gi + 72] -= *cp++;
            }
          }
          returnValue = sb_dataSize(ellipticCurve, m + 64);

再直观一点就是:
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 - (第0、2、4......26、28、30位用减法运算,比如第0位76-74=02h)
3 9 15 21 27 ^ (第3、9、15、21、27位用异或运算,例如第3位AB^74=DFh)
1 5 7 11 13 17 19 23 25 29 + (第1、5、7......23、25、29位用加法运算,例如第1位9D+65=02,注意取末两位)

0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30  <= 0~30(共31 = (1F)h位
76 9D E2 AB 3B 42 D7 6B 20 B5 46 39 ED BC A0 D1 CB 0B 5D 65 DC E5 39 63 44 80 CD 78 27 8C 17  <= pubkey in pubkey.h
74 65 73 74 6C 6D 64 74 65 73 74 6C 6D 64 74 65 73 74 6C 6D 64 74 65 73 74 6C 6D 64 74 65 73  <= testlmd
02 02 6F DF CF AF 73 DF BB C6 D2 A5 80 20 2C B4 58 7F F1 D2 78 91 D4 D6 D0 EC 60 1C B3 F1 A4  <= real pubkey(for SIGN2=)

存储在硬盘上的是lmpubkey.h里的public key,经过上面的转化变成真正的public key,所以只要找到lmpubkey中key的存放规律,替换公钥就水到渠成了,这个后面再讲。

(未完待续)


[培训]科锐逆向工程师培训第53期2025年7月8日开班!

上传的附件:
收藏
免费 9
支持
分享
最新回复 (29)
雪    币: 493
活跃值: (299)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
2
2014-9-14
太长了,另起一篇吧
2014-9-12 17:07
0
雪    币: 1790
活跃值: (635)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
研究挺仔细的,期待下文!
2014-9-12 17:08
0
雪    币: 319
活跃值: (2629)
能力值: ( LV12,RANK:980 )
在线值:
发帖
回帖
粉丝
4
强悍!值得学习。
2014-9-12 17:13
0
雪    币: 114
活跃值: (180)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
先支持再斟酌~
2014-9-12 17:52
0
雪    币: 135
活跃值: (63)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
6
留个名,有能力之后再学习
2014-9-12 17:57
0
雪    币: 341
活跃值: (153)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
7
图片好小。。。
2014-9-12 18:05
0
雪    币: 55
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
mark~替换公钥一直在研究中,期待下文。
2014-9-12 20:02
0
雪    币: 805
活跃值: (2698)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
好文,必须好好学!

楼主的插图根本无法看清,既然插了,能否换成清楚一点的?
2014-9-12 20:20
0
雪    币: 150
活跃值: (74)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
mark~替换公钥一直在研究中,期待下文。
2014-9-12 23:03
0
雪    币: 12019
活跃值: (18869)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
路过,帮楼主顶一下,看到密码的东西,就感觉头疼
2014-9-13 09:58
0
雪    币: 2
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
学习ECC公匙替换
2014-9-13 16:29
0
雪    币: 1113
活跃值: (761)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
请楼主发个Word,或者PDF版的吧,图片实在看不清啊
2014-9-13 21:56
0
雪    币: 493
活跃值: (299)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
14
抱歉,写得匆忙,是有点小,更新了大图了。
2014-9-14 09:30
0
雪    币: 1599
活跃值: (5198)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
15
learning
2014-9-16 13:15
0
雪    币: 7125
活跃值: (7800)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
16
学习,ECC公匙替换值得深入。谢谢楼主!

同时提醒楼主一下:下面论述里的 lmprikey.h 似乎应为 lmpubkey.h,恳请楼主检查一下

======================================
请注意下lmprikey.h里的内容,后面会用到
======================================
2014-10-22 08:31
0
雪    币: 26
活跃值: (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
期待视频教程,谁能出一个视频教程呀
2014-11-3 18:50
0
雪    币: 1351
活跃值: (2367)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
18
非常感谢楼分享!!!
2015-6-11 00:30
0
雪    币: 1
活跃值: (161)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
楼主,你给的没有daemon没法调试啊。。。
2015-8-7 13:57
0
雪    币: 200
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
研究挺仔细的,
2015-8-7 16:03
0
雪    币: 1
活跃值: (161)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
楼主,请教一下。上篇教程中ida中相应的sig文件有几个啊,是通过哪些文件生成的?我用lmgr.lib生成的sig文件不完整,并没有楼主的效果。
2015-8-9 21:49
0
雪    币: 230
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
這真的是太精華了~
謝謝分享實務經驗~
感謝~
2015-11-13 11:07
0
雪    币: 168
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
mark
2016-8-11 23:57
0
雪    币: 21
活跃值: (164)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
非常不错,mark一下
2018-4-25 16:20
0
雪    币: 220
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
25
很详细的教程,收藏了,感谢楼主。
不过有个疑问,我在 win10 用 ida 跟了一遍 testlmd,为什么找到的 pubkey 和楼主的不一样 
我找到的是:
76 9E 6A 55 C2 34 FD 24 0F 95 D1 29 BB F9 01 85 01 3A 53 17 2A 98 BF B3 62 76 EC 9A 87 69 53
计算后的是:
02 03 F7 21 56 A1 99 98 AA E6 5D 95 4E 5D 8D E0 8E AE E7 84 C6 EC 5A 26 EE E2 7F FE 13 CE E0
2019-2-18 10:08
0
游客
登录 | 注册 方可回帖
返回