首页
社区
课程
招聘
[原创]Python和《加密与解密》
2015-11-7 13:32 45068

[原创]Python和《加密与解密》

2015-11-7 13:32
45068
前些天在临时会员写的文章,现在转移到《加密与解密》版块下,以方便后来的学习者,能从本人的学习过程中学到一点东西,尤其是python的魅力
在加密与解密P59页 的实例1 使用IDC脚本实现“查看输入函数”,本人会点python,就对比用Python实现了,python脚本应该是趋势,希望加密与解密第4版能使用python吧。
def GetImportSeg():
    ea=FirstSeg()
    next=ea
    count=0
    while next != BADADDR: #判断是否为".idata"段
        next=NextSeg(next)
        name=SegName(next)
        if name[0:6]=='.idata':
            break
    return next

def main():
    BytePtr=SegStart(GetImportSeg()) #确定idata段VA
    EndImports=SegEnd(BytePtr)
    print('\n Parsing import table...')
    while  BytePtr<EndImports:
        if LineA(BytePtr,1):
            print( '__'+LineA(BytePtr,1)+'__')
        if Name(BytePtr):
            print(Name(BytePtr)+'\n') #显示当前地址的函数名
        BytePtr=NextAddr(BytePtr)
    print('Import table parsing complete\n')

if __name__=='__main__':
    main()

程序结果
Python>

Parsing import table...__; Virtual size                  : 000008B2 (   2226.)__
GetModuleFileNameA

CloseHandle

CreateFileA

GetStringTypeA

...........

Import table parsing complete

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞1
打赏
分享
最新回复 (44)
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2015-11-7 13:33
2
0
#!/usr/bin/env python
#coding:utf-8
#20151019 14:48  《加密与解密 3rd》P61 实例2 用IDC分析加密代码 IDAPython实现
#patch_byte(ea, x) -->bool   将解密数据放回原处

from idc import *

def decrypt (start,size,key):  
    s=start
    for i in range(size):
        x=Byte(start)^key
        patch_byte(start,x)
        start+=1
    print('Decrypted addr %s-%s successful!' %(hex(s),hex(start)))

if __name__=='__main__':
    decrypt(0x00401060,0x15,0x1)

命令行输出:
Decrypted addr 0x401060-0x401075 successful!

解密前:
.text:00401060 loc_401060:                             ; CODE XREF: sub_401020+Bp
.text:00401060                                         ; DATA XREF: sub_401080o
.text:00401060                 imul    esi, [ecx], 69h
.text:00401063                 sbb     eax, 69014131h
.text:00401068                 add     [ecx], esi
.text:0040106A                 inc     ecx
.text:0040106B                 add     [ebx+1], ebp
.text:0040106B ; ---------------------------------------------------------------------------
.text:0040106E                 dd 210D14FEh
.text:00401072                 db 41h
.text:00401073 ; ---------------------------------------------------------------------------
.text:00401073                 add     edx, eax        ; DATA XREF: sub_401080+Do
解密后
.text:00401060 ; ---------------------------------------------------------------------------
.text:00401060
.text:00401060 loc_401060:                             ; CODE XREF: sub_401020+Bp
.text:00401060                                         ; DATA XREF: sub_401080o
.text:00401060                 push    30h
.text:00401062                 push    offset unk_40301C
.text:00401067                 push    offset aWelcomToWww_pe ; "Welcom to www.pediy.com!"
.text:0040106C                 push    0
.text:0040106C ; ---------------------------------------------------------------------------
.text:0040106E                 dd 200C15FFh
.text:00401072                 db 40h
.text:00401073 ; ---------------------------------------------------------------------------
.text:00401073                 add     bl, al          ; DATA XREF: sub_401080+Do
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2015-11-7 13:35
3
0
今天看到加密与解密P65了,书中讲到修改程序的CrateWindowEx样式参数。首先CrateWindowEx是什么?其次,书上说的winuser.h头文件在哪里看?

对于我这样的新手,对于Windows API 如果查,怎么查,刚开始是不知道的,现在给初学的朋友说一下吧:
Windows API查询:百度“MSDN CrateWindowEx”,建议查看英文版本,中文翻译很差

Windows 头文件查看:(建议配合书做)
  环境:VC++ 2010 Express Edition(精简)或安装Windows SDK (完整)

        头文件:winuser.h

       WindowsAPI:https://msdn.microsoft.com/en-us/library/aa930455.aspx

         dwStyle参数:WS_HSCROLL,WS_VSCROLL

  查询头文件:
    WS_HSCROLL  0010 0000h
    WS_VSCROLL  0020 0000h

  参数运算(IDAPython,python做这种计算非常方便)
    多个参数使用XOR运算
    当前参数:0CF0000h

    >>>hex(0x00100000|0x00200000|0x0CF0000)
    结果:0xff0000

                注意:python使用0x作为16进制前缀,并非0cff0000h这种形式,不使用hex函数,结果将显示为10进制形式
上传的附件:
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2015-11-7 13:37
4
0
在这一章节,我发现注册机的可逆函数F2里,并未对表达式 k2=k2*10+code[i]-48  求逆,可是为什么呢?书写错了?去群里问了下才知道原因。

因为 charNum-48是用来字符转换数字的
单步分析
□ 核心代码
ODE:00401228                 push    offset String   ; Name='pediy'
ODE:0040122D                 call    sub_40137E      ; k1=F1('pediy')
ODE:00401232                 push    eax                    ; push k1
ODE:00401233                 push    offset byte_40217E ; serial='1234'
ODE:00401238                 call    sub_4013D8       ; k2=F2('1234')
ODE:0040123D                 add     esp, 4                ; balance stack
ODE:00401240                 pop     eax                    ; pop k1
ODE:00401241                 cmp     eax, ebx           ; cmp k1,k2
ODE:00401243                 jz      short loc_40124C ; equal jmp
ODE:00401245                 call    sub_401362
        
□ k1=F1('pediy')函数代码
大写字母ASCII范围41h~5Ah
小写字母ASCII范围61h~7Ah
CODE:0040137E             mov     esi, [esp+arg_0]      ;[ESP+4],'pediy'
CODE:00401382             push    esi
CODE:00401383             mov     al, [esi]                        ;取一个字符
CODE:00401385             test    al, al                              ;检查是否还有字符
CODE:00401387             jz      short loc_40139C       ;没有字符了,跳转
CODE:00401389             cmp     al, 41h                       ;41h uppercase 'A'
CODE:0040138B             jb      short loc_4013AC      ;非字母异常处理
CODE:0040138D             cmp     al, 5Ah                       ;5Ah uppercase 'Z'
CODE:0040138F             jnb     short loc_401394;非uppercase,则转换为大写(字母判断逻辑不完整)
CODE:00401391             inc     esi
CODE:00401392             jmp     short loc_401383
CODE:00401394 ; ---------------------------------------------------------------------------
CODE:00401394             call    sub_4013D2     ;Lower2UpperCase
CODE:00401399             inc     esi
CODE:0040139A             jmp     short loc_401383
CODE:0040139C ; ---------------------------------------------------------------------------
CODE:0040139C             pop     esi                            ;'PEDIY'
CODE:0040139D             call    sub_4013C2          ;对'PEDIY'变形处理
CODE:004013A2             xor     edi, 5678h              ;对得到的结果异或
CODE:004013A8             mov     eax, edi                 ;结果放入eax,准备结束当前子程序
CODE:004013AA             jmp     short locret_4013C1
CODE:004013AC ; ---------------------------------------------------------------------------
CODE:004013AC             pop     esi                           ; 如果输入非字母,出错
CODE:004013AD             push    30h         ; uType,Style
CODE:004013AF             push    offset aError   ; "Error!  ",Title
CODE:004013B4             push    offset aIncorrectTryAg ; "Incorrect!,Try Again",text
CODE:004013B9             push    dword ptr [ebp+8] ; hWnd
CODE:004013BC             call    MessageBoxA
CODE:004013C1             retn
CODE:004013C2 ; =============== S U B R O U T I N E ===============
CODE:004013C2             xor     edi, edi          ; ”PEDIY“变形处理,当前指令EDI clear
CODE:004013C4             xor     ebx, ebx
CODE:004013C6             mov     bl, [esi]                  ;"PEDIY"中取一个字符
CODE:004013C8             test    bl, bl
CODE:004013CA             jz      short locret_4013D1
CODE:004013CC             add     edi, ebx                  ;EDI=EDI+EBX
CODE:004013CE             inc     esi
CODE:004013CF             jmp     short loc_4013C6
CODE:004013D1             retn
CODE:004013D2 ; =============== S U B R O U T I N E
CODE:004013D2             sub     al, 20h
CODE:004013D4             mov     [esi], al
CODE:004013D6             retn

使用C语言描述上面的代码
          int F1(char *name)
          {
              int i,k1=0;
              char ch;
              for(i=0;name[i]!=0;i++)
              {
                  ch=name[i];
                  if (ch<'A') break;
                  k1+=(ch>'Z')?(ch-32):ch;
              }
              k1=k1^0x5678;
              return k1;
          }
         
□ k2=F2('1234')函数代码
CODE:004013D8          xor     eax, eax
CODE:004013DA          xor     edi, edi
CODE:004013DC          xor     ebx, ebx
CODE:004013DE          mov     esi, [esp+arg_0]       ;ESI指向输入的序列号code[i]
CODE:004013E2          mov     al, 0Ah
CODE:004013E4          mov     bl, [esi]
CODE:004013E6          test    bl, bl                             ;检查code[i]中的是否还有数字
CODE:004013E8          jz      short loc_4013F5
CODE:004013EA          sub     bl, 30h                        ;EBX=BL-30h=code[i]-30h
CODE:004013ED          imul    edi, eax                        ;EDI=EDI*10,10进制左移1位
CODE:004013F0          add     edi, ebx                       ;EDI=EDI+EBX=EDI+(code[i]-30h)
CODE:004013F2          inc     esi
CODE:004013F3          jmp     short loc_4013E2
CODE:004013F5 ;  ---------------------------------------------------------------------------
CODE:004013F5          xor     edi, 1234h                 ;最后对EDI做异或运算
CODE:004013FB          mov     ebx, edi
CODE:004013FD          retn

使用C语言描述上面的代码
          int F2(char *code)
          {
              int i,k2=0;
              for(i=0;code[i]!=0;i++)
              {
                  k2=k2*10+code[i]-48;
           //如果a的值为'0'到'9'这10个字符之一,则a-48相当于将字符转换为数值。
           //若a='5',则a-48=5。其中48是'0'的ASCII码
              }
              k2=k2^0x1234;
              return k2;
          }
         
注册机算法分析
        核心思路
          ® 只要满足k1=k2注册就成功;
          ® 写注册机就要对F1或F2做逆变换,F1('n')=F2('s')这样'n','s'间就可自由转换;
        算法选择
          ® 那么由F2=>F1方便,还是反过来方便 ?
          ® 如果从用户名算出序列号,只要找到F2的逆函数F1(name)=k1=F_2^(−1) (serial)
          ® 由于F_2^(−1) 函数有多个解
        注册机代码
          //注意:name[i]的位数是10位,原因见其调用的GetDlgItemTexstA函数
          int keygen(char *name)
          {
                  int i, k1 = 0,k2=0;
                  char ch;
                  for (i = 0;name[i] != 0&&i<=9;i++)
                  {
                          ch = name[i];
                          if (ch<'A') break;
                          k1 += (ch>'Z') ? (ch - 32) : ch;
                  }
                  k2 = k1 ^ 0x5678^0x1234;
                  return k2;
          }
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2015-11-7 13:44
5
0
#!/usr/bin/env python
#coding:utf-8
#2015-11-06 22:41:31

def maze():
    x=['2221','2223','2211','0100','1110','0333','1111','1211','0112','2332','3303','3222','3221','1100','1111','2233']
    retn='0b'
    #base4 conver to base2
    for ele in x:
        for atom in ele:
            retn+=bin(int(atom))[2:].zfill(2)
    retn=hex(int(retn,2))[2:].upper() #base2 to base16

    print('maze')
    for ele in range(int(len(retn)/4)):
        print(retn[ele*4:ele*4+4],end='  ')
    print()
    print('*'*52)
    return retn

def key(usr):
    sumX=0
    print('*'*52+'\n'+usr)
    for char in usr:
        sumX+=ord(char)
        print(str(hex(ord(char))[2:]),end='  ')
    print()
    print('*'*52)
    sumX='0x'+hex(sumX)[-2:]   #取求和结果低位8字节

    lost=maze()   #hex value "A9AB..."   #准备异或运算
    retn=''
    for pair in range(int(len(lost)/2)):
        result='0x'+lost[pair*2:pair*2+2]
        retn+=hex(int(result,16)^int(sumX,16))[2:].upper()

    print('key')
    for ele in range(int(len(retn)/4)):
        print(retn[ele*4:ele*4+4],end='  ')
    print()
    print('*'*52)
    return retn

if __name__=='__main__':
    key('pediy')

输出结果如下:(与P121页结果相同)

****************************************************
pediy
70  65  64  69  79
****************************************************
maze
A9AB  A510  543F  5565  16BE  F3EA  E950  55AF
****************************************************
key
B2B0  BEB4  F244  E7ED  A5E8  F1F2  4B4E
****************************************************
上传的附件:
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2015-11-7 13:45
6
0
注意:本人使用python3.5,python2.x将在2020年停止使用,而IDA还在使用python 2.7.5
,表示悲哀。。。
雪    币: 112
活跃值: (36)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
xietao 2015-11-7 14:52
7
0
Python调用api很方便, 就是数据转换麻烦点
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2015-11-14 21:45
8
0
5.6.2 网络验证破解的一般思路
使用python代码19行就可以搞定,IDC需要37行
#!/usr/bin/env python3
#coding: utf-8
#2015-11-14 19:56:17 P124 ch5.6.2

def getasm(fromX,to,range1,range2): #注意,python中from是系统关键字,不能当成变量使用,所以使用fromX
    fp=open(r'd:\code.txt','w')
    fp.write('地址\t\t指令\t\t\t\t//偏移\t访问内存\n')
    for ea in range(fromX,to+1):
        cmd=GetMnem(ea) #获取ea地址处汇编助记符,IDAapi
        if ( cmd[:3]=='mov' ) or ( cmd[:3]=='lea'):
            opcode=Dword(NextNotTail(ea)-4) #获取mov cl,byte ptr ds:[41AEB0]指令中的0x0041AEB0
            if opcode>0x80000000:
                opcode=opcode^((2**32)-1)+1  #计算负数的补码
            print('->%08x %08x' %(ea,opcode))

            if opcode>=range1 and opcode<=range2:
                delta=opcode-range1  #ebp - 256 -->256
                eaX=("%08x" %ea).upper()+'\t'
                opcode=("%08x" %opcode).upper()+'\t'
                fp.write(eaX+GetDisasm(ea)+'\t'+opcode+'\n')
                MakeComm(ea,("\t//ebp-0x%04x" %delta).upper());  #加注释到IDA中
    fp.close()
    print('finished!')

#getasm(0x401000,0x40F951,0x41AE68,0x41AEC1)

输出结果:
      地址                指令                                //偏移        访问内存
0040113D        mov     cl, byte_41AEB0 ;         //EBP-0X0048        0041AEB0       
004016B6        mov     byte_41AE68[eax], dl;         //EBP-0X0000        0041AE68       
004016C0        mov     cl, byte_41AE6C ;         //EBP-0X0004        0041AE6C       
004016D0        mov     dl, byte_41AE76 ;         //EBP-0X000E        0041AE76       
004016E7        mov     cl, byte_41AE72 ;         //EBP-0X000A        0041AE72       
004016F7        mov     dl, byte_41AE8B ;         //EBP-0X0023        0041AE8B       
00401707        mov     al, byte_41AEA4 ;         //EBP-0X003C        0041AEA4       
00401713        mov     cl, byte_41AEAA ;         //EBP-0X0042        0041AEAA       

书上的IDC代码
//《加密与解密》第三版
//code by DarkNess0ut

static Getasm(from ,to,range1,range2)
{
    auto ea,cmd,fp,deta,opcode;

    fp=fopen("c:\\code.txt","w");
    for (ea=from;ea<to;)
    {
        
        cmd=GetMnem(ea);
        if (strstr(cmd,"mov")==0 || strstr(cmd,"lea")==0 )
        {
            opcode=Dword(NextNotTail(ea)-4); //目标:获取mov cl,byte ptr ds:[41AEB0]指令中的41AEB0
            //mov cl,byte ptr ds:[41AEB0]机器码-->  8A0D B0AE4100

            if(opcode<0){//opcode<0处理 mov  edx, [ebp-350]指令,否则处理mov  edx, [ebp+350]
                opcode=~opcode;  //python (opcode^0xffffffff)+1
                opcode++;
            }
        

            Message("-> %08X %08X\n",ea,opcode); //print

            if (opcode>=range1 && opcode<=range2)
            {
                deta=opcode-range1;
                fprintf(fp,"%08X %s       //+0x%04X %08X\n",ea,GetDisasm(ea),deta,opcode); //格式化字串写到文件
                MakeComm (ea,form("// +0x%04X",deta));  //加注释到IDA中
            }
        }
        ea=NextNotTail(ea);
    } //for end
    fclose(fp);
    Message("OK!");
}
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2015-11-18 11:52
9
0
P132 ch6.1.1 MD5算法描述存在描述不清楚的问题,读者可参考下面的数学表达式来理解

第四步、四轮循环运算:循环的次数是分组的个数(N+1)

     1)将每一512字节细分成16个小组,每个小组64位(8个字节)
     
     2)先认识四个线性函数(&是与,|是或,~是非,^是异或)
  F(X,Y,Z)=(X&Y)|((~X)&Z)
  G(X,Y,Z)=(X&Z)|(Y&(~Z))
  H(X,Y,Z)=X^Y^Z
  I(X,Y,Z)=Y^(X|(~Z))
   
    3)设Mj表示消息的第j个子分组(从0到15),<<<s表示循环左移s位,则四种操作为:
  FF(a,b,c,d,Mj,s,ti)表示a=b+((a+F(b,c,d)+Mj+ti)<<<s)
  GG(a,b,c,d,Mj,s,ti)表示a=b+((a+G(b,c,d)+Mj+ti)<<<s)
  HH(a,b,c,d,Mj,s,ti)表示a=b+((a+H(b,c,d)+Mj+ti)<<<s)
  II(a,b,c,d,Mj,s,ti)表示a=b+((a+I(b,c,d)+Mj+ti)<<<s)
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2015-11-27 14:02
10
0
自己用python实现了下c语言版本的md5算法,python也提供hashlib库使用,但我想自己实现一下,加深理解,以方便以后写自定义算法。实践证明,下面的算法,运行效率相当低。

#!/usr/bin/env python
#coding:utf-8
#20151120 17:22

import sys
#------------------------------------init-------------------------------------
#Constans for MD5 transfrom routine
S11 = 7
S12 = 12
S13 = 17
S14 = 22
S21 = 5
S22 = 9
S23 = 14
S24 = 20
S31 = 4
S32 = 11
S33 = 16
S34 = 23
S41 = 6
S42 = 10
S43 = 15
S44 = 21

PADDING64 = [
0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

#define F,G,H,I  basic MD5 functions
f = lambda x,y,z: (x&y) | ((x^(0xffffffff))&z)
g = lambda x,y,z: (x&z) | (y&(z^(0xffffffff)))
h = lambda x,y,z: x^y^z
i = lambda x,y,z: y^(x | (z^0xffffffff))

#ROTATE_LEFT rotates x left n bits
rotate_left = lambda x,n: eval('0b'+bin(x<<n)[2:].zfill(32)[-32:]) | (x>>(32-n))

'''
    ff,gg,hh,ii transformations for rounds 1,2,3 and 4
    a,b,c,d is MD5 initialization constants
    eleM is 32bit of plaintext
    sinN = hex(int(abs((2**32)*sin(i)))) ,i=1~64
    rol -->rotate_left X bits
    f = lambda x,y,z: (x&y) | ((x^(0xffffffff)+1)&z)
'''
def ff(a,b,c,d,eleM,rolX,sinN):
    a+=f(b,c,d)+eleM+sinN
    a=eval('0x'+hex(a)[2:].zfill(8)[-8:])
    a=rotate_left(a,rolX)+b
    a=eval('0x'+hex(a)[2:].zfill(8)[-8:])
    return a

def gg(a,b,c,d,eleM,rolX,sinN):
    a+=g(b,c,d)+eleM+sinN
    a=eval('0x'+hex(a)[2:].zfill(8)[-8:])
    a=rotate_left(a,rolX)+b
    a=eval('0x'+hex(a)[2:].zfill(8)[-8:])
    return a

def hh(a,b,c,d,eleM,rolX,sinN):
    a+=h(b,c,d)+eleM+sinN
    a=eval('0x'+hex(a)[2:].zfill(8)[-8:])
    a=rotate_left(a,rolX)+b
    a=eval('0x'+hex(a)[2:].zfill(8)[-8:])
    return a

def ii(a,b,c,d,eleM,rolX,sinN):
    a+=i(b,c,d)+eleM+sinN
    a=eval('0x'+hex(a)[2:].zfill(8)[-8:])
    a=rotate_left(a,rolX)+b
    a=eval('0x'+hex(a)[2:].zfill(8)[-8:])
    return a

#----------------------------------end-------------------------------------------
class MD5(object):
    def __init__(self):
        #MD5 initialization constants ,countX-data block being processed
        #count --> count[2], (aa,bb,cc,dd) -->state[4], buffer64 -->context.buffer[64]
        self.count=0
        self.buffer64 = []       #ele -->ord(char)
        self.digestRaw16=[]  #ele -->ord(char)
        self.digestChars='' #ele --> [''3E","4D","10"...]
        #      char digestChars[ 33 ] ;
        #    for( pos = 0 ; pos < 16 ; pos++ )
        #      sprintf( digestChars+(pos*2), "%02x", digestRaw[pos] ) ;
        self.aa=self.a=0x67452301
        self.bb=self.b=0xefcdab89
        self.cc=self.c=0x98badcfe
        self.dd=self.d=0x10325476

    def decode(self,byteLst512):
        '''
            decode  512bit chars to 512bit numbers , total 64 ascii chars,
            every 4 chrs convert to 1 number
            byteLst512=open(FN,'rb').read(64) -> byteLst=[64,254,0,...]
            lst32=[ele32bitA,ele32bitB,...],     len(lst32)=16
            ele32 -->0x32303135 -->(LE) 0x35313032
        '''
        lst32=[]
        for i in range(int(64/4)):
            tmp=''
            for bit in byteLst512[i*4:i*4+4]:
                tmp+=hex(bit)[2:].zfill(2)
            lst32.append(eval('0x'+tmp[6:8]+tmp[4:6]+tmp[2:4]+tmp[0:2]))
        return lst32

    def encode(self,lst32):
        '''
        lst32= [ele32bitA,ele32bitB,...],     len(_out)=16 , type(ele32bitA)==int"
        _out=[ele4bitA,ele4bitB,...] -->byteLst
        Update( _out, Len ) -->
        MD5Transform( state[4], _out)
        '''
        tmp=''
        byteLst=[]
        for ele in lst32:
            tmp+=hex(ele)[2:].zfill(8)
        for idx in range(int(len(tmp)/2)):
            byteLst.append(eval('0x'+tmp[idx*2:idx*2+2]))
        return byteLst

    def md5Transform(self,chrLst64):
        x=self.decode(chrLst64)  #x=[ele32bitA,ele32bitB...]
        a=self.aa
        b=self.bb
        c=self.cc
        d=self.dd
        #Round 1

        a = ff (a, b, c, d, x[ 0], S11, 0xd76aa478)
        d = ff (d, a, b, c, x[ 1], S12, 0xe8c7b756)
        c = ff (c, d, a, b, x[ 2], S13, 0x242070db)
        b = ff (b, c, d, a, x[ 3], S14, 0xc1bdceee)
        a = ff (a, b, c, d, x[ 4], S11, 0xf57c0faf)
        d = ff (d, a, b, c, x[ 5], S12, 0x4787c62a)
        c = ff (c, d, a, b, x[ 6], S13, 0xa8304613)
        b = ff (b, c, d, a, x[ 7], S14, 0xfd469501)
        a = ff (a, b, c, d, x[ 8], S11, 0x698098d8)
        d = ff (d, a, b, c, x[ 9], S12, 0x8b44f7af)
        c = ff (c, d, a, b, x[10], S13, 0xffff5bb1)
        b = ff (b, c, d, a, x[11], S14, 0x895cd7be)
        a = ff (a, b, c, d, x[12], S11, 0x6b901122)
        d = ff (d, a, b, c, x[13], S12, 0xfd987193)
        c = ff (c, d, a, b, x[14], S13, 0xa679438e)
        b = ff (b, c, d, a, x[15], S14, 0x49b40821)

        #Round 2
        a=gg (a, b, c, d, x[ 1], S21, 0xf61e2562)
        d=gg (d, a, b, c, x[ 6], S22, 0xc040b340)
        c=gg (c, d, a, b, x[11], S23, 0x265e5a51)
        b=gg (b, c, d, a, x[ 0], S24, 0xe9b6c7aa)
        a=gg (a, b, c, d, x[ 5], S21, 0xd62f105d)
        d=gg (d, a, b, c, x[10], S22,  0x2441453)
        c=gg (c, d, a, b, x[15], S23, 0xd8a1e681)
        b=gg (b, c, d, a, x[ 4], S24, 0xe7d3fbc8)
        a=gg (a, b, c, d, x[ 9], S21, 0x21e1cde6)
        d=gg (d, a, b, c, x[14], S22, 0xc33707d6)
        c=gg (c, d, a, b, x[ 3], S23, 0xf4d50d87)
        b=gg (b, c, d, a, x[ 8], S24, 0x455a14ed)
        a=gg (a, b, c, d, x[13], S21, 0xa9e3e905)
        d=gg (d, a, b, c, x[ 2], S22, 0xfcefa3f8)
        c=gg (c, d, a, b, x[ 7], S23, 0x676f02d9)
        b=gg (b, c, d, a, x[12], S24, 0x8d2a4c8a)

        #Round 3
        a = hh (a, b, c, d, x[ 5], S31, 0xfffa3942)
        d = hh (d, a, b, c, x[ 8], S32, 0x8771f681)
        c = hh (c, d, a, b, x[11], S33, 0x6d9d6122)
        b = hh (b, c, d, a, x[14], S34, 0xfde5380c)
        a = hh (a, b, c, d, x[ 1], S31, 0xa4beea44)
        d = hh (d, a, b, c, x[ 4], S32, 0x4bdecfa9)
        c = hh (c, d, a, b, x[ 7], S33, 0xf6bb4b60)
        b = hh (b, c, d, a, x[10], S34, 0xbebfbc70)
        a = hh (a, b, c, d, x[13], S31, 0x289b7ec6)
        d = hh (d, a, b, c, x[ 0], S32, 0xeaa127fa)
        c = hh (c, d, a, b, x[ 3], S33, 0xd4ef3085)
        b = hh (b, c, d, a, x[ 6], S34,  0x4881d05)
        a = hh (a, b, c, d, x[ 9], S31, 0xd9d4d039)
        d = hh (d, a, b, c, x[12], S32, 0xe6db99e5)
        c = hh (c, d, a, b, x[15], S33, 0x1fa27cf8)
        b = hh (b, c, d, a, x[ 2], S34, 0xc4ac5665)

        #Round 4
        a = ii (a, b, c, d, x[ 0], S41, 0xf4292244)
        d = ii (d, a, b, c, x[ 7], S42, 0x432aff97)
        c = ii (c, d, a, b, x[14], S43, 0xab9423a7)
        b = ii (b, c, d, a, x[ 5], S44, 0xfc93a039)  #error
        a = ii (a, b, c, d, x[12], S41, 0x655b59c3)
        d = ii (d, a, b, c, x[ 3], S42, 0x8f0ccc92)
        c = ii (c, d, a, b, x[10], S43, 0xffeff47d)
        b = ii (b, c, d, a, x[ 1], S44, 0x85845dd1)
        a = ii (a, b, c, d, x[ 8], S41, 0x6fa87e4f)
        d = ii (d, a, b, c, x[15], S42, 0xfe2ce6e0)
        c = ii (c, d, a, b, x[ 6], S43, 0xa3014314)
        b = ii (b, c, d, a, x[13], S44, 0x4e0811a1)
        a = ii (a, b, c, d, x[ 4], S41, 0xf7537e82)
        d = ii (d, a, b, c, x[11], S42, 0xbd3af235)
        c = ii (c, d, a, b, x[ 2], S43, 0x2ad7d2bb)
        b = ii (b, c, d, a, x[ 9], S44, 0xeb86d391)

        self.aa += a
        self.aa=eval('0x'+hex(self.aa)[2:].zfill(8)[-8:])
        self.bb += b
        self.bb=eval('0x'+hex(self.bb)[2:].zfill(8)[-8:])
        self.cc += c
        self.cc=eval('0x'+hex(self.cc)[2:].zfill(8)[-8:])
        self.dd += d
        self.dd=eval('0x'+hex(self.dd)[2:].zfill(8)[-8:])

    def update(self,ordchrLst):
        '''
            pad self.buffer64 --> md5Transform
            update self.count bits(all process bits)
            md5Transform 512bit blocks
            remain ordchrLst store in self.buffer
        '''
        index=self.count%64
        partLen=64-index
        self.count+=len(ordchrLst)
        #pading self.buffer64
        if len(ordchrLst)>=partLen:
            self.buffer64.extend([ordchrLst.pop() for i in range(64-len(self.buffer64))])
            self.md5Transform(self.buffer64)
            loopN=int(len(ordchrLst)/64)
            for idx in range(loopN):
                self.md5Transform(ordchrLst[idx*64:idx*64+64])
            ordchrLst=ordchrLst[loopN*64:]
        else:
            self.buffer64.extend(ordchrLst)

    def final(self):
        '''
            padding len=448(mod512)
            append len(msg) -->64bits
            md5Transform --> hash val
        '''
        if self.count > 2**64:
            self.count=self.count & (2**64-1)
        tmp=hex(self.count<<3)[2:].zfill(16)
        bits=[]
        for idx in range(int(len(tmp)/2)):
            bits.append(eval('0x'+tmp[idx*2:idx*2+2]))
        index=self.count % 64
        padLen=0
        if index < 56:
            padLen=56 - index
        else:
            padLen=120 - index
        self.update(PADDING64[:padLen])
        self.update(bits)

        lst=[]
        tmp=[self.aa,self.bb,self.cc,self.dd]  #LE
        for ele in tmp:
            ele=hex(ele)[2:].zfill(8)
            ele=eval('0x'+ele[6:9]+ele[4:6]+ele[2:4]+ele[0:2])
            lst.append(ele)
        tmp=lst
        self.digestRaw16=self.encode(tmp)

        for ele in tmp:
            self.digestChars+=hex(ele)[2:].zfill(2)

    def digestFile(self,filename):
        self.__init__()
        try:
            f=open(filename,'rb')
        except Exception as e:
            print(str(e))
            sys.exit(1)
        buf=list(f.read(1024))
        while buf:
            self.update(buf)
            buf=list(f.read(1024))
        self.final()
        f.close()
        return self.digestChars

    def digestMemory(self,idx,size):
        self.__init__()
        from ctypes import string_at
        msg=list(string_at(idx,size))  #b'.....' -->list
        self.update(msg)
        self.final()
        return self.digestChars

    def digestString(self,strX):
        self.__init__()
        strX=list(str(strX).encode('utf-8'))  #string --> ord(charX)
        self.update(strX)
        self.final()
        return self.digestChars

if __name__ == '__main__':
    x=MD5()
    filename='d:/a.txt'
    print('File:',x.digestFile(filename))
    print('Mem:',x.digestMemory(id(filename),64))
    print('Mem:',x.digestMemory(id(filename),64))
    print('Str:',x.digestString('teststr'))
雪    币: 1787
活跃值: (340)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
yezhulove 2015-11-27 16:33
11
0
from hashlib import md5
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2015-11-29 22:10
12
0
谢谢!我只是想尝试自己实现一下,加深对md5 c源码的理解
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2015-12-7 19:06
13
0
7处优化及debug

一. 初始化参数必须再次分别核实
  循环左移参数debug
    S44=2        S44=21
  
二. Python与C的 ~num差异
  C语言        ~num会直接对bit值进行取反
  python         ~num==num^0xffffffff
  
三. C UINT4与Python hex(num)字节序
  typedef unsigned long int UINT4;  //32bit 4Bytes
  UINT4 x=2864434397  # dd cc bb aa
  x=hex(2864434397) #aa bb  cc  dd
  在C语言中,数据的存储是以LE字节序的形式,而python的hex是BE,因此注意转换代码时的字节序;
  而C的 undesigned char x[]="...."与py 的x="..."在字节序上是一致的。
四. C的静态数据类型与Python的动态类型
  UINT4 state[4];
  a=state[0];
  a+=f(b,c,d)+eleM+sinN; //C语言不需要虚拟数据长度,因为是固定的
  a+=f(b,c,d)+eleM+sinN
a=eval('0x'+hex(a)[2:].zfill(8)[-8:]) //Py是解释语言,解释时动态确定类型,数据长度需要截断
  
五. 保留"32位" 用字串切片很低效,a&0xffffffff提升效率
  a=12345678901234567890
a=eval('0x'+hex(a)[2:].zfill(8)[-8:])
a=a&0xffffffff
  >>> hex(a)
'0xeb1f0ad2'
  使用上面的方面优化ff,gg,hh,ii函数后,计算1.29MB的程序用时18-21秒,优化前44.75秒
  
六. 使用ctypes模块中的数据类型,提升位操作效率
  rotate_left = lambda x,n: eval('0b'+bin(x<<n)[2:].zfill(32)[-32:]) | (x>>(32-n))
  a=eval('0x'+hex(a)[2:].zfill(8)[-8:])
  def rotate_left(x,n):
    x=c_uint(x)
    x.value=(x.value<<n) | (x.value>>(32-n))
    return x.value
  def ff(a,b,c,d,eleM,rolX,sinN):
    a=c_uint(a)   #ctypes.c_uint 4Bytes
    a.value+=f(b,c,d)+eleM+sinN
    a.value=rotate_left(a.value,rolX)+b
    return a.value
  使用上面的方面优化ff,gg,hh,ii及rotate_left函数后,计算1.29MB的程序用时7-8秒
  
  self.bb=0x10325476
  self.bb += b
self.bb=self.bb&0xffffffff
  self.dd=c_uint(0x10325476)
self.dd.value += d
  
七. 移位处理BE LE的转换,提升处理效率
  def decode(self,byteLst512):
        '''
            decode  512bit chars to 512bit numbers , total 64 ascii chars,
            every 4 chrs convert to 1 number
            byteLst512=open(FN,'rb').read(64) -> byteLst=[64,254,0,...]
            lst32=[ele32bitA,ele32bitB,...],     len(lst32)=16
            ele32 -->0x32303135 -->(LE) 0x35313032
        '''
        lst32=[]
        for i in range(int(64/4)):
            tmp=''
            for bit in byteLst512[i*4:i*4+4]:
                tmp+=hex(bit)[2:].zfill(2)
            lst32.append(eval('0x'+tmp[6:8]+tmp[4:6]+tmp[2:4]+tmp[0:2]))
        return lst32
  def decodeX(self,byteLst512):
        lst32=[]
        for idx in range(int(64/4)):
            sublst=byteLst512[idx*4:idx*4+4]
            lst32.append(sublst[0] | (sublst[1]<<8) | \
                    (sublst[2]<<16) | (sublst[3]<<24))
        return lst32
  使用上面的方面优化函数后,计算1.29MB的程序用时3.75秒
  
      def encode(self,lst32):
        '''
        lst32= [ele32bitA,ele32bitB,...],     len(_out)=16 , type(ele32bitA)==int"
        _out=[ele4bitA,ele4bitB,...] -->byteLst
        Update( _out, Len ) -->
        MD5Transform( state[4], _out)
        '''
        tmp=''
        byteLst=[]
        for ele in lst32:
            tmp+=hex(ele)[2:].zfill(8)
        for idx in range(int(len(tmp)/2)):
            byteLst.append(eval('0x'+tmp[idx*2:idx*2+2]))
        return byteLst
      def encode(self,lst32):  
        '''
        lst32= [ele32bitA,ele32bitB,...],     len(byteLst)=16 , type(ele32bitA)==int"
        byteLst=[ele4bitA,ele4bitB,...] -->byteLst,type(ele4bitA)==int
        '''
        byteLst=[]
        for ele in lst32:
            byteLst.append(ele&0xff)
            byteLst.append((ele>>8)&0xff)
            byteLst.append((ele>>16)&0xff)
            byteLst.append((ele>>24)&0xff)
        return byteLst
  
   def final(self):
        '''
            padding len=448(mod512)
            append len(msg) -->64bits
            md5Transform --> hash val
        '''
        if self.count > 2**64:
            self.count=self.count & (2**64-1)
        #encode self.count -->
        tmp=hex(self.count<<3)[2:].zfill(16)
        bits=[]
        for idx in range(int(len(tmp)/8)):
            bits.append(eval('0x'+tmp[idx*8+6:idx*8+8]))
            bits.append(eval('0x'+tmp[idx*8+4:idx*8+6]))
            bits.append(eval('0x'+tmp[idx*8+2:idx*8+4]))
            bits.append(eval('0x'+tmp[idx*8:idx*8+2]))
        bits=bits[4:8]+bits[0:4]
        index=self.count % 64
        padLen=0
        if index < 56:
            padLen=56 - index
        else:
            padLen=120 - index
        self.update(PADDING64[:padLen])
        self.update(bits)
            lst=[]
        tmp=[self.aa.value,self.bb.value,self.cc.value,self.dd.value]  #LE
        for ele in tmp:
            ele=hex(ele)[2:].zfill(8)
            ele=eval('0x'+ele[6:9]+ele[4:6]+ele[2:4]+ele[0:2])
            lst.append(ele)
        tmp=lst
        self.digestRaw16=self.encode(tmp)
  def final(self):
        '''
            padding len=448(mod512)
            append len(msg) -->64bits
            md5Transform --> hash val
        '''
        count = [self.count[0],self.count[1]]
        bits=self.encode(count)  #return byteLst,size=64bits
      
        index=(self.count[0]>>3) &0x3f  #self.count[0]_bytes mod 64
        if index < 56:
            padLen=56 - index
        else:
            padLen=120 - index
             self.update(PADDING64[:padLen])
        self.update(bits)
        self.digestRaw16=('%#x %#x %#x %#x' \
            %(self.aa.value,self.bb.value,self.cc.value,self.dd.value)).split()
            tmp=self.encode([self.aa.value,self.bb.value,self.cc.value,self.dd.value])
        self.digestChars=''.join([hex(i)[2:].zfill(2) for i in tmp])
  
八. 使用ctypes array来保持C代码与Py代码一致性
  def update(self,ordchrLst):
        '''
            pad self.buffer64 --> md5Transform
            update self.count bits(all process bits)
            md5Transform 512bit blocks
            remain ordchrLst store in self.buffer
          '''
        index=len(self.buffer64)%64
        partLen=64-index
            self.count+=len(ordchrLst)
        #pading self.buffer64
        if len(ordchrLst)>=partLen:
            self.buffer64.extend([ordchrLst.pop(0) for i in range(64-len(self.buffer64))])
            self.md5Transform(self.buffer64)
            self.buffer64=[]
            loopN=int(len(ordchrLst)/64)
            for idx in range(loopN):
                self.md5Transform(ordchrLst[:64])
                ordchrLst=ordchrLst[64:]
            self.buffer64.extend(ordchrLst)
        else:
            self.buffer64.extend(ordchrLst)
  def update(self,ordchrLst):
        '''
            pad self.buffer64 for md5Transform()
            update self.count bits(all process bits)
            md5Transform 512bit blocks
            remain ordchrLst store in self.buffer64
          self.count=c_uint*2
          '''
        index=len(self.buffer64)%64
        partLen=64-index
        inputLen=len(ordchrLst)
        self.count[0]+=inputLen<<3   #bytes -->bits
        if self.count[0] < inputLen:
            self.count[1]+=1
        self.count[1]+=inputLen>>29
  #pading self.buffer64
        if len(ordchrLst)>=partLen:
            self.buffer64.extend(ordchrLst[:partLen])
            ordchrLst=ordchrLst[partLen:]
            self.md5Transform(self.buffer64)
            self.buffer64=[]
            loopN=int(len(ordchrLst)/64)
            for idx in range(loopN):
                self.md5Transform(ordchrLst[:64])
                ordchrLst=ordchrLst[64:]
            self.buffer64.extend(ordchrLst)
        else:
            self.buffer64.extend(ordchrLst)
  

cpp源代码行 360行
py源代码行   285行
代码优化  44.89-3.75秒  约12倍
理解md5.cpp,补充C++基础,模仿成md5.py,debug ,py ctypes模块学习:2015.11.20-2015.12.7
雪    币: 2
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xxd小飞 2015-12-16 23:17
14
0
你好 能否留一个联系方式找你看一个python程序
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2015-12-23 11:34
15
0
....NA....
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2015-12-23 11:39
16
0
http://pan.baidu.com/s/1i4ehh2l  代码程序

一、小张爱审计

小张服务器被溢出攻击了,小张很苦恼,女朋友也说他无能。然而这个可恶的黑客却告诉小张他的服务器ip和一个小文件,并说他等着小张报复哈哈哈,小张很愤怒,大家一起进攻坏蛋吧(flag文件在/home/ctf/flag.txt文件中,答案为flag{}形式,提交{}内内容即可)。
nc 192.168.1.2 8888

二、文件类型分析   IDA 识别为ELF文件
   
   
三、平台及编译器分析
    由IDA Pro逆向关键字 call    ___isoc99_scanf 可知,程序为Linux平台GCC编译器编译生成的C语言代码,综合上一分析,查知应用为i386平台应用,需要linux 32平台
   
四、NC了解
    Netcat is a simple Unix utility which reads and writes data across network connections, using TCP or UDP protocol.
    In the simplest usage, "nc host port" creates a TCP connection to the given port on the given target host.  Your standard input is then sent to the host, and anything that comes back across the connection is sent to your standard output.  This continues indefinitely, until the network side of the connection shuts down.  Note that this behavior is different from most other applications which shut everything down and exit after an end-of-file on the standard input.
   
五、代码分析,查找溢出点
5.1溢出点原理:
程序对"user name" "password" 参数都做了输入长度检查(边界安全检查),但对用户的输入信息"Pls input the  information: "未做边界检查,导致用户可输入任意长度的数据,覆盖堆栈的返回地址,返回地址如果精心构造,可反弹一个bash shell提供给远程恶意用户,进而控制受害服务器端。
.text:0804865A                 lea    eax,[ebp-0x110],由核心代码定位分析,得知,用户从输入信息开始的110个字节后开始构造shellcode即可实现溢出攻击。
根据题目提示:"nc 172.13.4.19 8888" 需要使用nc工具连接服务器指定端口,猜测需要远程运行服务端程序,在本地构造"Pls input the  information: "信息,服务器端通过nc反弹一个linux shell到本地,本地通过此shell,访问/home/ctf/flag.txt文件,获取flag {value},从而得到正确答案。

5.2 使用IDA Pro工具,配合GCC objdump分析反汇编代码,代码及注释如下
$objdump -D -M intel 567504000c6d6  >> 567504000c6d6.asm
.text:080484B0                 public start
.text:080484B0 start           proc near
.text:080484B0                 xor     ebp, ebp
.text:080484B2                 pop     esi
.text:080484B3                 mov     ecx, esp
.text:080484B5                 and     esp, 0FFFFFFF0h
.text:080484B8                 push    eax
.text:080484B9                 push    esp
.text:080484BA                 push    edx
.text:080484BB                 push    offset sub_8048750
.text:080484C0                 push    offset sub_8048760
.text:080484C5                 push    ecx
.text:080484C6                 push    esi
.text:080484C7                 push    offset sub_804870A ; welcome to beijing
.text:080484CC                 call    ___libc_start_main
.text:0804870A sub_804870A     proc near               ; DATA XREF: start+17o
.text:0804870A                 push    ebp
.text:0804870B                 mov     ebp, esp
.text:0804870D                 and     esp, 0FFFFFFF0h
.text:08048710                 sub     esp, 10h
.text:08048713                 mov     dword ptr [esp], offset aWelcomeToBeiji ; "welcome to Beijing"
.text:0804871A                 call    _puts  ;char a[20]="xiaosan";puts(a);        //字符串输出
.text:0804871F                 mov     eax, ds:stdout
.text:08048724                 mov     [esp], eax      ; stream
.text:08048727                 call    _fflush              ;int fflush(FILE* stream);
.text:0804872C                 call    sub_804859C     ; input usr name
.text:0804859C                 push    ebp
.text:0804859D                 mov     ebp, esp
.text:0804859F                 sub     esp, 168h
.text:080485A5                 mov     dword ptr [esp], offset format ; "Pls input the user name : "
.text:080485AC                 call    _printf
.text:080485B1                 mov     eax, ds:stdout
.text:080485B6                 mov     [esp], eax      ; stream
.text:080485B9                 call    _fflush
.text:080485BE                 lea     eax, [ebp+s]
.text:080485C4                 mov     [esp+4], eax
.text:080485C8                 mov     dword ptr [esp], offset aS ; "%s"
.text:080485CF                 call    ___isoc99_scanf
.text:080485D4                 lea     eax, [ebp+s]
.text:080485DA                 mov     [esp], eax      ; s
;----------------------敏感代码--------------------------------------
.text:080485DD                 call    _strlen
.text:080485E2                 cmp     eax, 20h        ;用户名最大允许32个英文字符
.text:080485E5                 jbe     short loc_80485F3 ;  input password
;---------------------------------------------------------------------
    .text:080485F3                 mov     dword ptr [esp], offset aPlsInputThePas ; "Pls input the password : "
.text:080485FA                 call    _printf
.text:080485FF                 mov     eax, ds:stdout
.text:08048604                 mov     [esp], eax      ; stream
.text:08048607                 call    _fflush
.text:0804860C                 lea     eax, [ebp+var_130]
.text:08048612                 mov     [esp+4], eax
.text:08048616                 mov     dword ptr [esp], offset aS ; "%s"
.text:0804861D                 call    ___isoc99_scanf
.text:08048622                 lea     eax, [ebp+var_130]
.text:08048628                 mov     [esp], eax      ; s
;----------------------敏感代码--------------------------------------
.text:0804862B                 call    _strlen
.text:08048630                 cmp     eax, 20h ;密码最大允许32个英文字符
.text:08048633                 jbe     short loc_8048641 ; input info
;---------------------------------------------------------------------
.text:08048641                 mov     dword ptr [esp], offset aPlsInputTheInf ; "Pls input the  information: "
.text:08048648                 call    _printf
.text:0804864D                 mov     eax, ds:stdout
.text:08048652                 mov     [esp], eax      ; stream
.text:08048655                 call    _fflush
;----------------------溢出点代码--------------------------------------
.text:0804865A                 lea    eax,[ebp-0x110]
.text:08048660                 mov     [esp+4], eax                       ;&stringX
.text:08048664                 mov     dword ptr [esp], offset aS ; "%s"
.text:0804866B                 call    ___isoc99_scanf                     ;scanf("%s",&stringX)
;---------------------------------------------------------------------
.text:08048670                 mov     dword ptr [esp], offset s ; "I_Need_BMW"
.text:08048677                 call    _strlen         ;len("I_Need_BMW") == 10
.text:0804867C                 mov     [ebp+var_10], eax
.text:0804867F                 mov     [ebp+var_C], 0
.text:08048686                 jmp     short loc_80486BD
.text:080486BD loc_80486BD:                            ; CODE XREF: sub_804859C+EAj
.text:080486BD                 cmp     [ebp+var_C], 9
.text:080486C1                 jle     short loc_8048688
{
.text:08048688                 lea     edx, [ebp+s1] ;<__isoc99_scanf@plt+0x1e8>
.text:0804868E                 mov     eax, [ebp+var_C]  ;len("I_Need_BMW")
.text:08048691                 add     eax, edx
.text:08048693                 movzx   ecx, byte ptr [eax]
.text:08048696                 mov     eax, [ebp+var_C]
.text:08048699                 mov     edx, eax
.text:0804869B                 sar     edx, 1Fh
.text:0804869E                 idiv    [ebp+var_10]
.text:080486A1                 mov     eax, edx
.text:080486A3                 movzx   eax, byte ptr s[eax] ; "I_Need_BMW"
.text:080486AA                 xor     eax, ecx
.text:080486AC                 lea     ecx, [ebp+s1]
.text:080486B2                 mov     edx, [ebp+var_C]
.text:080486B5                 add     edx, ecx
.text:080486B7                 mov     [edx], al
.text:080486B9                 add     [ebp+var_C], 1
.text:080486BD
.text:080486BD loc_80486BD:                            ; CODE XREF: sub_804859C+EAj
.text:080486BD                 cmp     [ebp+var_C], 9  ; var_c = 0
.text:080486C1                 jle     short loc_8048688
}
.text:080486C3                 mov     dword ptr [esp], offset s2 ; "The_Pursuit_of_Happiness"
.text:080486CA                 call    _strlen
.text:080486CF                 mov     [esp+8], eax    ; n
.text:080486D3                 mov     dword ptr [esp+4], offset s2 ; "The_Pursuit_of_Happiness"
.text:080486DB                 lea     eax, [ebp+s1]
.text:080486E1                 mov     [esp], eax      ; s1
.text:080486E4                 call    _memcmp
.text:080486E9                 test    eax, eax
.text:080486EB                 jz      short loc_80486F6
.text:080486ED                 mov     [ebp+var_10F], 0CCh  ;input info addr
.text:080486F4                 jmp     short locret_8048708    ;程序结束
.text:080486F6                 mov     [ebp+var_106], 0CCh
.text:080486FD                 lea     eax, [ebp+s1]
.text:08048703                 add     eax, 1
.text:08048706                 call    eax
   
六、溢出点测试
6.1程序正常测试
$gdb 567504000c6d6
(gdb) r
Starting program: /root/python/now/567504000c6d6
welcome to Beijing
Pls input the user name : root
Pls input the password : admin
Pls input the  information: fsociety
[Inferior 1 (process 8138) exited normally]  //程序正常结束状态
   
6.2 超长文本溢出测试
当文本长度为68*4字节时,产生堆栈溢出异常,可根据此特点,构造shellcode代码,通过恶意程序获取shell,控制过程服务器
>>> '\x00'*68   #python shell
(gdb) r
Starting program: /root/python/now/567504000c6d6
welcome to Beijing
Pls input the user name : o
Pls input the password : o
Pls input the  information: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
Program received signal SIGSEGV, Segmentation fault.  //程序异常结束,说明堆栈出现异常,刚好验证了溢出漏洞
0x3030785c in ?? ()  //堆栈
(gdb)
   
七、高级语言代码理解原理(C语言)
printf("Pls input the  information: ");
fflush(stdout)  //立刻清空输出缓冲区,并把缓冲区内容输出
char stringX[] = ''
scanf("%s",&stringX);
//正常情况,需要对stringX的长度做严格检查,防止stringX的内容覆盖了“后续代码函数返回地址”,从而达到恶意目的
....后续代码...
雪    币: 191
活跃值: (788)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
Netfairy 11 2015-12-23 12:45
17
0
感谢分享
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2016-1-15 21:37
18
0
#!/usr/bin/env python3
# coding: utf-8
# 2016-01-06 23:08:46
# Be care of BE LE

from hashlib import md5
from ctypes import c_uint32
from sys import exit

DELTA = 0x9e3779b9
BLOCK_SIZE = 2  # number of 32-bit ints
KEY_SIZE = 4
ROUNDS = 32
SUMATION = 0xc6ef3720

def encrypt_block(block, key, verbose=False):
    ''' Encrypt a single 64-bit block with a 128-bit key
    @param block: list of two c_uint32s
    @param key:  list of four c_uint32s
    '''
    assert len(block) == BLOCK_SIZE
    assert len(key) == KEY_SIZE
    s = c_uint32(0)
    delta = c_uint32(DELTA)
    for idx in range(ROUNDS):
        s.value += delta.value
        block[0].value += \
            ((block[1].value << 4) + key[0].value) ^ \
            (block[1].value + s.value) ^\
            ((block[1].value >> 5) + key[1].value)
        block[1].value += \
            ((block[0].value << 4) + key[2].value) ^\
            (block[0].value + s.value) ^\
            ((block[0].value >> 5) + key[3].value)
        if verbose:
            print('\t --> Encrypting block round %d of %d' % (idx + 1, ROUNDS))
    return block

def decrypt_block(block, key, verbose=False):
    '''Decrypt a single 64-bit block with 128-bit key
    @param block: list of two c_uint32s
    @param key:  list of four c_uint32s
    '''
    assert len(block) == BLOCK_SIZE
    assert len(key) == KEY_SIZE
    s = c_uint32(SUMATION)
    delta = c_uint32(DELTA)
    for idx in range(ROUNDS):
        block[1].value -=\
            ((block[0].value << 4) + key[2].value) ^\
            (block[0].value + s.value) ^\
            ((block[0].value >> 5) + key[3].value)
        block[0].value -=\
            ((block[1].value << 4) + key[0].value) ^\
            (block[1].value + s.value) ^\
            ((block[1].value >> 5) + key[1].value)
        s.value -= delta.value
        if verbose:
            print('\t<-- Decrypting block round %d of %d' % (idx +1, ROUNDS))
    return block

def to_c_array(string):
    '''Convert a string to a list of c_uint32s'''
    c_array = []
    for idx in range(0, len(string), 8):
        x = int(string[idx:idx+8], 16)
        # convert BE to LE
        x = ((x >> 24) & 0xff) | ((x >> 16) & 0xff) << 8 |\
            ((x >> 8) & 0xff) << 16 | (x&0xff) << 24
        c_array.append(c_uint32(x))
    return c_array

def to_string(c_array):
    '''Converts a list of c_uint32s to a Python (ascii) string'''
    tmp = []
    for idx in range(len(c_array)):
        x = c_array[idx].value
        x = ((x >> 24) & 0xff) | ((x >> 16) & 0xff) << 8 |\
            ((x >> 8) & 0xff) << 16 | (x&0xff) << 24
        tmp.append(x)

    output = ''
    for block in tmp:
        output += hex(block)[2:].zfill(8)
    return output.upper()

def xor(c_arrayX, c_arrayY):
    '''every bits of c_arrayX xor per c_arrayY's
    @param c_arrayX: list of two c_uint32s
    @param c_arrayY: list of two c_uint32s
    output: bytes list
    '''
    output = []
    for idx in range(2):
        x = c_arrayX[idx].value
        y = c_arrayY[idx].value
        output.append(c_uint32((x  & 0xff) ^ (y & 0xff) |\
            (((x>>8)&0xff) ^ ((y>>8)&0xff)) << 8 |\
            (((x>>16)&0xff) ^ ((y>>16)&0xff)) << 16 |\
            (((x>>24)&0xff) ^ ((y>>24)&0xff)) << 24))
    return output

def main():
    name = input('usr: ').strip()
    assert len(name) != 0
    m = md5()
    m.update(name.encode('ascii'))

    k = to_c_array(m.hexdigest())
    v = [k[2], k[3]]
    v = xor(v, k)
    v = decrypt_block(v, k)
    print(to_string(v))
    #return to_string(v)

if __name__ == "__main__":
    main()
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2016-3-30 19:52
19
0
#!/usr/bin/env python3
#coding: utf-8
#2015-12-24 22:27:21
#总结:当xor等数值运行较多时,最好使用list,而非str来保存serial
from hashlib import sha1

def keyGen(name):
    s=sha1()
    s.update(name.encode('utf-8'))
    hashHex =list(s.digest())
    lstA = list(b'PEDIY Forum')+[0]
    lstB = lstA[:]

    idx = 0
    while idx < 17:
        lstB.append(hashHex[idx] ^ lstB[idx])
        idx += 1  
    lstA = lstB[len(lstA):]

    lstB = b'pediy.com'
    while idx < 20:
        lstA.append(hashHex[idx] ^ lstB[idx - 17])
        idx += 1

    for idx in range(10):
        lstA[idx]  ^= lstA[idx+10]

    result = ''.join([hex(i)[2:].zfill(2) for i in lstA]).upper()
    return result[:20]

if __name__ == '__main__':
    name = input('name :\t').strip()
    print(keyGen(name))
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2016-3-30 19:53
20
0
#!/usr/bin/env python3
# coding: utf-8
# 2016-01-06 23:08:46
# Be care of BE LE

from hashlib import md5
from ctypes import c_uint32
from sys import exit

DELTA = 0x9e3779b9
BLOCK_SIZE = 2  # number of 32-bit ints
KEY_SIZE = 4
ROUNDS = 32
SUMATION = 0xc6ef3720

def encrypt_block(block, key, verbose=False):
    ''' Encrypt a single 64-bit block with a 128-bit key
    @param block: list of two c_uint32s
    @param key:  list of four c_uint32s
    '''
    assert len(block) == BLOCK_SIZE
    assert len(key) == KEY_SIZE
    s = c_uint32(0)
    delta = c_uint32(DELTA)
    for idx in range(ROUNDS):
        s.value += delta.value
        block[0].value += \
            ((block[1].value << 4) + key[0].value) ^ \
            (block[1].value + s.value) ^\
            ((block[1].value >> 5) + key[1].value)
        block[1].value += \
            ((block[0].value << 4) + key[2].value) ^\
            (block[0].value + s.value) ^\
            ((block[0].value >> 5) + key[3].value)
        if verbose:
            print('\t --> Encrypting block round %d of %d' % (idx + 1, ROUNDS))
    return block

def decrypt_block(block, key, verbose=False):
    '''Decrypt a single 64-bit block with 128-bit key
    @param block: list of two c_uint32s
    @param key:  list of four c_uint32s
    '''
    assert len(block) == BLOCK_SIZE
    assert len(key) == KEY_SIZE
    s = c_uint32(SUMATION)
    delta = c_uint32(DELTA)
    for idx in range(ROUNDS):
        block[1].value -=\
            ((block[0].value << 4) + key[2].value) ^\
            (block[0].value + s.value) ^\
            ((block[0].value >> 5) + key[3].value)
        block[0].value -=\
            ((block[1].value << 4) + key[0].value) ^\
            (block[1].value + s.value) ^\
            ((block[1].value >> 5) + key[1].value)
        s.value -= delta.value
        if verbose:
            print('\t<-- Decrypting block round %d of %d' % (idx +1, ROUNDS))
    return block

def to_c_array(string):
    '''Convert a string to a list of c_uint32s'''
    c_array = []
    for idx in range(0, len(string), 8):
        x = int(string[idx:idx+8], 16)
        # convert BE to LE
        x = ((x >> 24) & 0xff) | ((x >> 16) & 0xff) << 8 |\
            ((x >> 8) & 0xff) << 16 | (x&0xff) << 24
        c_array.append(c_uint32(x))
    return c_array

def to_string(c_array):
    '''Converts a list of c_uint32s to a Python (ascii) string'''
    tmp = []
    for idx in range(len(c_array)):
        x = c_array[idx].value
        x = ((x >> 24) & 0xff) | ((x >> 16) & 0xff) << 8 |\
            ((x >> 8) & 0xff) << 16 | (x&0xff) << 24
        tmp.append(x)

    output = ''
    for block in tmp:
        output += hex(block)[2:].zfill(8)
    return output.upper()

def xor(c_arrayX, c_arrayY):
    '''every bits of c_arrayX xor per c_arrayY's
    @param c_arrayX: list of two c_uint32s
    @param c_arrayY: list of two c_uint32s
    output: bytes list
    '''
    output = []
    for idx in range(2):
        x = c_arrayX[idx].value
        y = c_arrayY[idx].value
        output.append(c_uint32((x  & 0xff) ^ (y & 0xff) |\
            (((x>>8)&0xff) ^ ((y>>8)&0xff)) << 8 |\
            (((x>>16)&0xff) ^ ((y>>16)&0xff)) << 16 |\
            (((x>>24)&0xff) ^ ((y>>24)&0xff)) << 24))
    return output

def main():
    name = input('usr: ').strip()
    assert len(name) != 0
    m = md5()
    m.update(name.encode('ascii'))

    k = to_c_array(m.hexdigest())
    v = [k[2], k[3]]
    v = xor(v, k)
    v = decrypt_block(v, k)
    print(to_string(v))
    #return to_string(v)

if __name__ == "__main__":
    main()
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2016-3-30 20:51
21
0
因为《加密与解密》SHA密码学章节中,未使用IDA 进行分析,本着扎实打基础的原则,没太关注IDA 的使用,导致MD5和SHA算法的分析,完全是在汇编+Ollydbg的状态下进行,去逆向群问了下老司机,推荐说用F5, 我一看IDA 伪代码傻眼了...于是开始关注“伪代码vs汇编vs源代码” 三者关系,方便加速逆向分析。下面是一段函数的三者关系分析,未接触过IDA伪代码的朋友感受下。

汇编代码
.text:00401040                 mov     eax, [esp+sh]
.text:00401044                 push    esi
.text:00401045                 mov     esi, [esp+4+byte]
.text:00401049                 mov     ecx, [eax]      ; length[0]
.text:0040104B                 and     esi, 0FFh
.text:00401051                 shr     ecx, 5          ; sh->length[0]/32
.text:00401054                 and     ecx, 0Fh        ; cnt=(int)((sh->length[0]/32)%16);
.text:00401057                 mov     edx, [eax+ecx*4+28h] ; sh->w[cnt]
.text:00401057                                         ; sh+40->&w[0]
.text:0040105B                 shl     edx, 8          ; sh->w[cnt]<<=8;
.text:0040105E                 or      edx, esi
.text:00401060                 pop     esi
.text:00401061                 mov     [eax+ecx*4+28h], edx ; sh->w[cnt]|=(unsigned int)(byte&0xFF);
.text:00401065                 mov     ecx, [eax]      ; sh->length[0]+=8;
.text:00401067                 add     ecx, 8
.text:0040106A                 mov     [eax], ecx
.text:0040106C                 jnz     short loc_40107B ; if (sh->length[0]==0L):
.text:0040106E                 mov     ecx, [eax+4]
.text:00401071                 mov     dword ptr [eax], 0 ; sh->length[0]=0L;
.text:00401077                 inc     ecx
.text:00401078                 mov     [eax+4], ecx    ; sh->length[1]++
.text:0040107B
.text:0040107B loc_40107B:                             ; CODE XREF: sha1_process+2Cj
.text:0040107B                 test    dword ptr [eax], 1FFh ; if ((sh->length[0]%512)==0)
.text:00401081                 jnz     short locret_40108A
.text:00401083                 push    eax
.text:00401084                 call    sha1_transform  ; sha1_transform(sh);
.text:00401089                 pop     ecx
.text:0040108A                 retn
.text:0040108A sha1_process    endp

  人工翻译伪代码
ecx = (ecx >> 5) & 0xf
edx = structx[4 * ecx + 10 * c_int] << 8
edx |= esi & 0xff
structx[0] += 8
if stuctx[0] != 0:
    if stuctx[0] & 255 != 0:
        return eax
    else:
        func401090()
else:
    stuctx[1] += 1

IDA 伪代码
    int __cdecl sha1_process(int sh, unsigned __int8 byte)
{
  int result; // eax@1
  bool blx; // zf@1
  int v4; // ecx@2
    result = sh;
  *(_DWORD *)(sh + 4 * ((*(_DWORD *)sh >> 5) & 0xF) + 40) =
  byte | (*(_DWORD *)(sh+ 4 * ((*(_DWORD *)sh >> 5) & 0xF)+ 40) << 8);
  // cnt=(int)((sh->length[0]/32)%16); 对应等号左侧
  // sh->w[cnt]|(unsigned int)(byte&0xFF); 对应等号右侧
  blx = *(_DWORD *)sh == -8;                    // sh->w[cnt]<<=8;
                                                                      // if (sh->length[0]==0L){}
  *(_DWORD *)sh += 8;                           // sh->length[0]+=8;
  if ( blx )
  {
    v4 = *(_DWORD *)(sh + 4);                   //  sh->length[1]++;
    *(_DWORD *)sh = 0;
    *(_DWORD *)(sh + 4) = v4 + 1;               // sh->length[0]=0L;
  }
  if ( !(*(_DWORD *)sh & 0x1FF) )
    result = sha1_transform(sh);
  return result;
}

  源代码如下
typedef struct {
unsigned int length[2]; // sha
unsigned int h[8];  // sha + 8
unsigned int w[80]; //sha + 40
} sha;
    void sha1_process(sha *sh,int byte)
{ /* process the next message byte */
    int cnt;
   
    cnt=(int)((sh->length[0]/32)%16);
   
    sh->w[cnt]<<=8;
    sh->w[cnt]|=(unsigned int)(byte&0xFF);
    sh->length[0]+=8;
    if (sh->length[0]==0L) { sh->length[1]++; sh->length[0]=0L; }
    if ((sh->length[0]%512)==0) sha1_transform(sh);
}
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2016-4-1 15:50
22
0
<加密与解密> 这本书加密算法一章,最虐心的,除了这前的IDEA算法(Debian专利,找不到合适加密库)比较虐心以外,就是AES算法了,复习密码学数论,看源代码,分析IDA伪代码,汇编代码关系。。。

下面上python 注册机主程序
# !/usr/bin/env python3
# coding: utf-8
# 2016-04-01 00:55:58

import string
from hashlib import md5
from binascii import unhexlify, hexlify

from Crypto.Cipher import AES  # pip install pycrypto

KEY = [0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C]

def ishex(s):
    assert type(s) is str
    hex_digits = set(string.hexdigits)
    return all(c in hex_digits for c in s)

# 验证序列号是否正确
def aes_verify(name, serial):
    assert type(name) is str
    assert type(serial) is str
    assert len(serial) == 0x20
    assert ishex(serial), 'serial must be hex digits'
    global KEY
    aes = AES.new(bytes(KEY), AES.MODE_ECB)  # AES.new(key, AES.MODE_CBC, IV)
    ciphertext = aes.encrypt(unhexlify(serial))
    m = md5()
    m.update(name.encode('ascii'))
    if ciphertext == m.digest():
        return 'Verifyed successful!'
    else:
        return 'Verifyed Wrong!'

# 由用户名生成序列号
def aes_keygen(name):
    assert type(name) is str
    global KEY
    m = md5()
    m.update(name.encode('ascii'))
    aes = AES.new(bytes(KEY), AES.MODE_ECB)
    szSerial = aes.decrypt(m.digest())
    return hexlify(szSerial)

if __name__ == '__main__':
    while True:
        name = input('name >').strip()
        print(aes_keygen(name).upper().decode('ascii'))
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2016-4-1 16:26
23
0
在逆向分析过程中,总是要梳理函数逻辑,以理解程序做了什么,之前没有找到好的方法,导致逆向速度低下,现在算不上效率高,但好在用python 语言来描述逻辑过程,可以简化过程。下面是我的一些笔记,新手朋友可以参考下

import string
from binascii import unhexlify
from hashlib import md5

# ollydbg 内存数据分析函数,注意,OD 中的数据以 little-endian 形式显示
s = '''20 DE 87 7D AB 1F 7A 0E'''
def rev(s):
    s = s.split()
    s = ['0x' + i for i in s]
    s = str(s).replace("'", '')
    print(s)

def endian32(lst):
    assert len(lst) & 3 == 0
    for idx in range(0, len(lst), 4):
        lst[idx: idx + 4] = reversed(lst[idx: idx + 4])
    return lst

def ishex(s):
    assert type(s) is str
    hex_digits = set(string.hexdigits)
    return all(c in hex_digits for c in s)
###############################################

name = 'ipediy'
serial = '00112233445566778899AABBCCDDEEFF'
key = [0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C]

# 2B 7E 15 16 28 AE D2 A6 AB F7 15 88 09 CF 4F 3C
assert len(serial) == 0x20
assert ishex(serial)

xSeri = list(unhexlify(serial))
assert xSeri == [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]

m = md5()
m.update(name.encode('ascii'))
szHash = list(m.digest())
assert szHash == [0x84, 0x81, 0xE5, 0x7B, 0x16, 0x7B, 0xA7, 0x84, 0xA6, 0xB5, 0x78, 0x8B, 0x01, 0x89, 0xCE, 0x4C]

# .text:00401274  aes_init(ctx, 0, 0x10, key)
ctx = [0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C, 0xA0, 0xFA, 0xFE, 0x17, 0x88,
...
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

# pip install pycrypto
from Crypto.Cipher import AES
a = AES.new(bytes(key), AES.MODE_ECB)
ciphertext = a.encrypt(bytes(xSeri))
assert list(ciphertext) == [0x8D, 0xF4, 0xE9, 0xAA, 0xC5, 0xC7, 0x57, 0x3A, 0x27, 0xD8, 0xD0, 0x55, 0xD6, 0xE4, 0xD6, 0x4B]

assert ciphertext == szHash, 'Success!'
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2016-5-4 21:51
24
0
#!/usr/bin/env python3
# coding: utf-8
# 2016-05-04 21:24:18

from xmath import mulinv
from cryptocommon import ascii_to_int

def rsa_keygen(name, p, q, e):
    c = ascii_to_int(name)
    n = p * q
    phi = (p - 1) * (q - 1)
    d = mulinv(e, phi)
    m = pow(c, d, n)
    return hex(m)[2:].upper()

if __name__ == '__main__':
    name = input('name : ')
    e = 0x10001
    n = 0x80C07AFC9D25404D6555B9ACF3567CF1
    # p, q is decomposition by rsa-tool2 by TE
    p = 0xA554665CC62120D3
    q = 0xC75CB54BEDFA30AB
    print('serial: {}'.format(rsa_keygen(name, p, q, e)))

# xmath 是自己实现的加密库,最近学习RSA算法实现的,涉及大数运算的实现
# xmath.py
#!/usr/bin/env python
# coding: utf-8
# 2016-04-19 10:34:12
# pip install gmpy2 (need visual studio vc compiler)

# return (g, x, y)  a*x + b*y = gcd(x, y)
def xgcd(b, n):
    x0, x1, y0, y1 = 1, 0, 0, 1
    while n != 0:
        q, b, n = b // n, n, b % n
        x0, x1 = x1, x0 - q * x1
        y0, y1 = y1, y0 - q * y1
    return (b, x0, y0)

# gcd for python2, the same with py3's math.gcd
def gcd(a, b):
    return xgcd(a, b)[0]

# x = mulinv(b) mod n
def mulinv(b, n):
    g, x, _ = xgcd(b, n)
    if g == 1:
        return x % n

def xpow(x, y, n):
    if y < 0:
        x, y = mulinv(x, n), -y
    return pow(x, y, n)

# (x / y) % n, x.bit_length() > 2048
def xdiv(x, y, n):
    g = xgcd(x, y)[0]
    x, y = x // g, y // g
    y = mulinv(y, n)
    return (x * y) % n

if __name__ == '__main__':
    N = 23927411014020695772934916764953661641310148480977056645255098192491740356525240675906285700516357578929940114553700976167969964364149615226568689224228028461686617293534115788779955597877965044570493457567420874741357186596425753667455266870402154552439899664446413632716747644854897551940777512522044907132864905644212655387223302410896871080751768224091760934209917984213585513510597619708797688705876805464880105797829380326559399723048092175492203894468752718008631464599810632513162129223356467602508095356584405555329096159917957389834381018137378015593755767450675441331998683799788355179363368220408879117131
    c1 = 14548997380897265239778884825381301109965518989661808090688952232381091726761464959572943383024428028270717629953894592890859128818839328499002950828491521254480795364789013196240119403187073307558598496713832435709741997056117831860370227155633169019665564392649528306986826960829410120348913586592199732730933259880469229724149887380005627321752843489564984358708013300524640545437703771424168108213045567568595093421366224818609501318783680497763353618110184078118456368631056649526433730408976988014678391205055298782061128568056163894010397245301425676232126267874656710256838457728944370612289985071385621160886
    c2 = 12793942795110038319724531875568693507469327176085954164034728727511164833335101755153514030256152878364664079056565385331901196541015393609751624971554016671160730478932343949538202167508319292084519621768851878526657022981883304260886841513342396524869530063372782511380879783246034751883691295368172069170967975561364277514063320691930900258017293871754252209727301719207692321798229276732198521711602080244950295889575423383308099786298184477668302842952215665734671829249323604032320696267130330613134368640401070775927197554082071807605399448960911234829590548855031180158567578928333030631307816223152118126597
    m1 = 8246074182642091125578311828374843698994233243811347691229334829218700728624047916518503687366611595562099039411430662968666847086659721231623198995017758424796091810259884653332576136128144958751327844746991264667007359518181363522934430676655236880489550093852524801304612322373542296281962196795304499711006801211783005857297362930338978872451934860435597545642219213551685973208209873623909629278321181485010964460652298690058747090298312365230671723790850998541956664376820820570709272500330966205578898690396706695024001970727864091436518202414166919020415892764617055978488996164642229582717493375419993187360
    m2 = 15575051453858521753108462063723750986386093067763948316612157946190835527332641201837062951012227815568418309166473080588354562426066694924364886916408150576082667797274000661726279871971377438362829402529682825471299861814829463510659258586020732228351258291527965822977048954720558973840956731377322516168809373640494227129998871167089589689796024458501705704779109152762373660542684880052489213039920383757930855300338529058000330103359636123251274293258
    r1 = 12900676191620430360427117641859547516838813596331616166760756921115466932766990479475373384324634210232168544745677888398849094363202992662466063289599443
    r2 = 7718975159402389617924543100113967512280131630286624078102368166185443466262861344357647019797762407935675150925250503475336639811981984126529557679881059
    _, a, b = xgcd(r1, r2)
    k = xpow(xdiv(c1,  m1, N), a, N) * xpow(xdiv(c2, m2, N), b, N) % N
    print(k)
    # 175971776542095822590595405274258668271271366360140578776612582276966567082080372980811310146217399585938214712928761559525614866113821551467842221588432676885027725038849513527080849158072296957428701767142294778752742980766436072183367444762212399986777124093501619273513421803177347181063254421492621011961

# ascii_to_int 函数实现
from binascii import hexlify, unhexlify
def ascii_to_int(s):
        n = s.encode('ascii')
        return int(hexlify(n), 16)
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zwfy 2016-5-4 22:01
25
0
在对 p171页的RSA keyGenMe 反汇编的过程中,遇到很多Miracl 标准加密库函数,自己分析很费力,对照源代码看,也发现源代码理解起来也比较费力,去理解加密库源代码,貌似偏离了学逆向的初衷,幸好大神 Nil 相助,让我使用库签名,自己google 找到fireeye的技术文章
https://www.fireeye.com/blog/threat-research/2015/01/flare_ida_pro_script.html
上面提到FLARE 程序,发现IDA_Pro_v6.8 目录下有这个程序,flair68.zip,然后认真阅读readme.txt,将\6.3 公开密钥加密算法\6.3.1 RSA算法\RSAKeyGenMe\RSAKeyGenMe\src\ms32.lib 库制作成*.sig 然后使用IDA pro载入,未知函数就可以识别了,具体细节就不说了,读者自己找 flair68.zip 的readme看吧
游客
登录 | 注册 方可回帖
返回