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

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

2015-11-7 13:32
45447
收藏
免费 3
支持
分享
最新回复 (44)
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
26
继续完善自己的加密函数库,为以后CTF 做准备,就是不知道方面偏没有,上代码
#!/usr/bin/env python
# coding: utf-8
# 2016-05-04 23:40:39 加密解密 P173 密码编码学与网络安全 P287

from random import randint, getrandbits
from math import gcd
from xmath import mulinv, xgcd, xpow
from isprime import genprime

def elgamal_sig_init(size):
    '''
    @size: int, size > msg
    y = a^x mod q
    it's difficult to find random prime root 'a'
    '''
    x = q = genprime(size)
    a = randint(2, q - 2)
    size = q.bit_length()
    while x >= q:
        x = getrandbits(size)
    y = pow(a, x, q)
    return (q, a, x, y)

def elgamal_sig(m):
    '''
    @m: int, msg < q
    s1 = a^k mod q
    M = (x*s1 + k * s2) mod (q - 1) -> s2
    pub_key -> (a, q, y)
    pri_key -> x
    signature -> (s1, s2)
    '''
    q, a, x, y = elgamal_sig_init()
    k = randint(2, q -2)
    while gcd(k, q - 1) != 1:
        k = randint(2, q - 2)
    s1 = pow(a, k, q)
    k_inv = mulinv(k, q - 1)
    s2 = k_inv * (m - x * s1) % (q - 1)
    return (m, a, q, y, s1, s2)

def elgamal_sig_verify(args):
    '''
    (y^s1) * (s1^s2) = a^m mod p
    '''
    m, a, q, y, s1, s2 = args
    v1 = pow(a, m, q)
    v2 = pow(y, s1, q) * pow(s1, s2, q) % q
    return True if v1 == v2 and 1<= a < p else False

def ready(size):
    '''
    y = g^x mod p
    a = g^k mod p
    b = y^k mod p
    1 < g, k, x < p - 1
    pub_key -> (a, b, p)
    pri_key -> (a, b, p, x)
    '''
    x = p = genprime(size)
    k = randint(2, p - 2)
    while gcd(k, p - 1) != 1:
        k = randint(2, p - 2)
    g = randint(2, p - 2)
    while x >= p:
        x = getrandbits(size)
    y = pow(g, x, p)
    a = pow(g, k, p)
    b = pow(y, k, p)
    return (a, b, p, x)

# args = ready(n)
def crypto(m, a, b, p):
    b = m * b % p
    return (a, b)

def decrypt(a, b, p, x):
    ax = pow(a, x, p)
    inv = mulinv(ax, p)
    m = b * inv % p
    return m

if __name__ == '__main__':
    # m < 0xCE892335578D3F
    m = 1124
    sig = elgamal_sig(m)
    print(sig)
    print(elgamal_sig_verify(sig))

# genprime
from random import randint
from random import getrandbits

def find_kq(n):
    q = n - 1
    k = 1
    while not (q & 1):
        q >>= 1
        k += 1
    return k , q

# n > 2
def isprime(n):
    assert n > 2
    if n & 1 == 0:
        return False
    k, q = find_kq(n)
    a = randint(1, n - 1)
    if pow(a, q, n) == 1:  # 优化 a ** q % n
        return True
    for j in range(k):
        if pow(a, pow(2, j) * q, n) == n - 1:  # a **((2 ** j) * q) % n
            return True
    return False

# RSA 推荐 bit_length = 1024, 约6.84s 生成一个素数, 2048 约 15s, 平均测试 log(2**1024,e)//2 = 70次
def genprime(bit_length):
    while True:
        x = getrandbits(bit_length) # 比 randint() 快3.9倍以上
        if isprime(x):
            return x

# mulinv
# 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)

# x = mulinv(b) mod n
def mulinv(b, n):
    g, x, _ = xgcd(b, n)
    if g == 1:
        return x % n
2016-5-6 15:18
0
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
27
代码变量命名,按照ElgamalKGM.c 的源代码命名方式,方便阅读,注册机后续奉上

#!/usr/bin/env python
# coding: utf-8
# 2016-05-09 22:34:39  P177 ch6.3.2 Elgamal KeyGenMe 逻辑代码 python 等价实现

from hashlib import md5

def check(name, serial):
    # type(name)  == type(serial) == str
    assert True if name and serial else False, 'Wrong Serial !'
    if '-' not in serial:
        return False
    m = md5()
    m.update(b'ped')
    m.update(name.encode('ascii'))
    szHash =m.hexdigest()
    M = int(szHash, 16)
    # 4DB4A765FD4F0809A881A78966456945
    szSerial = serial.split('-')
    try:
        a, b= [int(i, 16) for i in szSerial]
    except:
        print('Wrong Serial !')
        return False
    p = 0xCE892335578D3F
    g = 0x473FE7D24CB6A6
    y = 0xA3CCD85BBD896
    result1 = pow(y, a, p)
    result2 = pow(a, b, p)
    result3 = result1 * result2 % p
    result4 = pow(g, M, p)
    if result4 == result3:
        print('success')
        return True
    else:
        print('Wrong Serial !')
        return False

if __name__ == '__main__':
    name = 'ipediy'
    serial = 'ACD47530E2ED99-295158D2AAA31B'
    check(name, serial)  # True
2016-5-9 22:54
0
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
28
加密与解密_光盘\chap06\6.3 公开密钥加密算法\6.3.2 ElGamal公钥算法

#!/usr/bin/env python
# coding: utf-8
# 2016-05-10 15:15:22 P177 ch6.3.2 Elgamal KeyGenMe

from sys import version
from random import randint
from hashlib import md5
from binascii import hexlify
from math import gcd
from xmath import mulinv

if 'v2.7' in version:
    input = raw_input

def keygen(name):
    assert type(name) is str
    p = 0xCE892335578D3F
    g = 0x473FE7D24CB6A6
    y = 0xA3CCD85BBD896
    x = 0x264D8D82C7AAB8
    k = randint(2, p -2)
    m = md5()
    m.update(b'ped')
    m.update(name.encode('ascii'))
    szHash =m.hexdigest()
    M = int(szHash, 16)
    while gcd(k, p - 1) != 1:
        k = randint(2, p - 2)
    s1 = pow(g, k, p)
    k_inv = mulinv(k, p - 1)
    s2 = k_inv * (M - x * s1) % (p - 1)
    serial = hex(s1)[2:].upper() + '-' + hex(s2)[2:].upper()
    return serial

def check(name, serial):
    # type(name)  == type(serial) == str
    assert True if name and serial else False, 'Wrong Serial !'
    if '-' not in serial:
        return False
    m = md5()
    m.update(b'ped')
    m.update(name.encode('ascii'))
    szHash =m.hexdigest()
    M = int(szHash, 16)
    # 4DB4A765FD4F0809A881A78966456945
    szSerial = serial.split('-')
    try:
        a, b= [int(i, 16) for i in szSerial]
    except:
        print('Wrong Serial !')
        return False
    p = 0xCE892335578D3F
    g = 0x473FE7D24CB6A6
    y = 0xA3CCD85BBD896
    result1 = pow(y, a, p)
    result2 = pow(a, b, p)
    result3 = result1 * result2 % p
    result4 = pow(g, M, p)
    if result4 == result3:
        print('success')
        return True
    else:
        print('Wrong Serial !')
        return False

if __name__ == '__main__':
    name = 'ipediy'
    serial = 'ACD47530E2ED99-295158D2AAA31B'
    check(name, serial)  # True
    # RDLP Tools v1.12  y = g^x mod p --> x = 0x264D8D82C7AAB8  614s(Try 486711703 cnts)
    while True:
        s = keygen(input('name > '))
        print('serial > {}'.format(s))
'''output
name > pediy
serial > 9390FD5DA9F5F-7F98F18EEDEE21
name > pediy
serial > 9494C8510B670D-C440133310FD6B
name > pediy
serial > 45C7449F72112D-4B0ED5382A89D5
name > pediy
serial > B1B6C76E5EF311-13CCA372E41A3B
'''
2016-5-10 17:19
0
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
29
#!/usr/bin/env python
# coding: utf-8
# 2016.5.27 19:31
from random import randint, getrandbits
from xmath import mulinv
from isprime import genprime

def modular_sqrt(a, p):
    """ Find a quadratic residue (mod p) of 'a'. p
        must be an odd prime.

        Solve the congruence of the form:
            x^2 = a (mod p)
        And returns x. Note that p - x is also a root.

        0 is returned is no square root exists for
        these a and p.

        The Tonelli-Shanks algorithm is used (except
        for some simple cases in which the solution
        is known from an identity). This algorithm
        runs in polynomial time (unless the
        generalized Riemann hypothesis is false).
    """
    # Simple cases
    #
    if legendre_symbol(a, p) != 1:
        return 0
    elif a == 0:
        return 0
    elif p == 2:
        return p
    elif p % 4 == 3:
        return pow(a, (p + 1) // 4, p)

    # Partition p-1 to s * 2^e for an odd s (i.e.
    # reduce all the powers of 2 from p-1)
    #
    s = p - 1
    e = 0
    while s % 2 == 0:
        s //= 2
        e += 1
   
    # Find some 'n' with a legendre symbol n|p = -1.
    # Shouldn't take long.
    #
    n = 2
    while legendre_symbol(n, p) != -1:
        n += 1

    # Here be dragons!
    # Read the paper "Square roots from 1; 24, 51,
    # 10 to Dan Shanks" by Ezra Brown for more
    # information
    #

    # x is a guess of the square root that gets better
    # with each iteration.
    # b is the "fudge factor" - by how much we're off
    # with the guess. The invariant x^2 = ab (mod p)
    # is maintained throughout the loop.
    # g is used for successive powers of n to update
    # both a and b
    # r is the exponent - decreases with each update
    #
    x = pow(a, (s + 1) // 2, p)
    b = pow(a, s, p)
    g = pow(n, s, p)
    r = e

    while True:
        t = b
        m = 0
        for m in range(r):
            if t == 1:
                break
            t = pow(t, 2, p)

        if m == 0:
            return x

        gs = pow(g, 2 ** (r - m - 1), p)  # wiki var(b)
        g = (gs * gs) % p  # wiki var(c`)
        x = (x * gs) % p   # x^2 = a*t mod p, if t == 1 then x is square root
        b = (b * g) % p    # wiki var(t`)
        r = m              # x -> wiki var(r`), r -> wiki var(j)

def legendre_symbol(a, p):
    """ Compute the Legendre symbol a|p using
        Euler's criterion. p is a prime, a is
        relatively prime to p (if p divides
        a, then a|p = 0)

        Returns 1 if a has a square root modulo
        p, -1 otherwise.
    """
    ls = pow(a, (p - 1) // 2, p)
    return -1 if ls == p - 1 else ls

def nfa(n):
    size = n.bit_length()
    o = [(n >> i) & 1 for i in range(size - 1, -1, -1)]
    o.insert(0, 0)
    j = 0
    for i in range(size - 1, -1, -1):
        if o[i] == o[i + 1] == 1:
            j += 1
            continue
        if j != 0:
            o[i: i + j + 2] = [1] + [0] * j + [-1]
            j = 0
    return o

class ECC(object):
    '''
    ECC(size [, p, B, A])
    ECC(0, p [, B, A])
    p.bit_length() == 256, (p, B) will be randomly generated
    >>> c = ECC(size = 256)  # p.bit_length() == 256, (p, B) will be randomly generated
   
    A = -3 by default, also you can specify another value
    >>> c = ECC(p=23, B=17, A=9)  # y^2 = x^3 + Ax + B (mod p)
    >>> P = (16, 5)
    Caution: Not all points(x, y) on elliptic curves, x belogs to Zp
    >>> Q = (20, c.gety(20)[0])  # gety(x) -> (y1, y2) or False
    >>> Q == (20, 3)
    >>> (16, 18) == c.eccplus(P, Q)
    >>> (7, 3) == c.eccmul(6, P)
    '''
    def __init__(self, size=0, p=0, B=0, A=-3):
        assert (size == p == 0) is False, 'ECC(size, p, B, A) -> size must give'
        self.size = size  # size bits
        self.p = p
        self.B = B
        if self.p == 0:
            while True:
                p = genprime(size)
                if p % 4 == 3:
                    self.p = p
                    break
        self.A = A % p
        if self.B == 0:
            self.getab()
        else:
            self.checkab()
        if self.size == 0:
            self.size = p.bit_length()

    def getab(self):
        A = self.A
        p = self.p
        while True:
            # a, b belong to Z_p
            B = randint(0, p)
            # be confirm as a abelian group
            if (4 * A ** 3 + 27 * B ** 2) % p != 0:
                self.B = B
                break

    def checkab(self):
        if (4 * self.A ** 3 + 27 * self.B ** 2) % self.p == 0:
            raise ValueError('A, B is invalid, try another!')

    def getdistlaw(self):
        ''' get quadratic residue distribution law of mod(p)'''
        p = self.p
        if p == 2:
            return 0
        return (p - 1) // 2

    def gety(self, x):
        A = self.A
        B = self.B
        p = self.p
        a = (x ** 3 + A * x + B) % p
        y1 = modular_sqrt(a, p)
        if y1 == 0:
            return False
        y2 = -y1 % p
        return y1, y2

    def eccplus(self, P, Q):
        try:
            assert type(P) is type(Q) is tuple and len(P) == len(Q) == 2
        except AssertionError:
            print('eccplus(P, Q) -> P or Q must be (x, y) tuple')
            return False
        p = self.p
        x1, y1 = P
        x2, y2 = Q
        if P == (0, 0) or Q == (0, 0):
            return (x1 + x2, y1 + y2)
        if x1 == x2 and y1 == -y2 % p:
            return 0, 0
        if P != Q:
            _lambda = ((y2 - y1) * mulinv(x2 - x1, p)) % p
        else:
            _lambda = (3 * x1 * x1 + self.A) * mulinv(2 * y1, p) % p
        x3 = (_lambda * _lambda - x1 - x2) % p
        y3 = (_lambda * (x1 - x3) - y1) % p
        return (x3, y3)
   
    def eccmul2(self, n, P):
        # n * P  
        try:
            assert type(n) is int and type(P) is tuple and len(P) == 2
        except AssertionError:
            print('eccmul(n, P), n must be int, P must be (x, y) tuple')
            return False
        if n <= 0:
            return 0, 0
        x3, y3 = P
        for i in range(n - 1):
            x3, y3 = self.eccplus(P , (x3, y3))
        return x3, y3  # Q = nP

    def eccmul(self, n, P):
        # double_and algorithm
        o = nfa(n)
        Q = (0, 0)
        for c in o:
            Q = self.eccplus(Q, Q)
            if c == 1:
                Q = self.eccplus(Q, P)
            elif c == -1:
                Q = self.eccplus(Q, (P[0], -P[1]))
        return Q

class ECIES(ECC):
    def __init__(self, args=None, A=0, B=0, p=0):
        '''
        o = ECIES() # ECIES(size=160)
        o = ECIES(224) # ECIES(size=224) init for enrypt
        o = ECIES(prikey, pubkey) # init for decrypt
        o = ECIES(pubkey) # init for encrypt
        o = ECIES(prikey) # init for decrypt
        '''
        if A & B & p != 0:
            super(ECIES, self).__init__(A=A, B=B, p=p)
            self.init()
        elif args == None:
            super(ECIES, self).__init__(size=160)
            self.init()
        elif type(args) == int:
            super(ECIES, self).__init__(size=args)
        elif len(args) == 2 and type(args[1]) == int:
            prikey = args
            p, A, B, P = prikey[0]
            self.d = prikey[1]
            super(ECIES, self).__init__(p=p, A=A, B=B)
        elif len(args) == 2 and len(args[1]) == 2 and type(args[1][1]) == int:
            pubkey = args
            p, A, B, P = pubkey[0]
            super(ECIES, self).__init__(p=p, A=A, B=B)
            self.Q = pubkey[1]
        elif len(args) == 2 and len(args[1]) == 2 and \
                type(args[1][1]) == tuple and \
                len(args[1][1]) == 2:
            prikey, pubkey = args
            p, A, B, P = pubkey[0]
            super(ECIES, self).__init__(p=p, A=A, B=B)
            self.Q = pubkey[1]
            self.d = prikey[1]
        else:
            raise ValueError('ECIES({}'.format(args))

    def init(self, size=160):
        # size = 112, 160, 224, 256, 384, 512
        # RSA    512,1024,2048,3072,7680,15360
        self.P = self.getP()
        self.prikey, self.pubkey = self.getkey(self.P)
        self.d = self.prikey[1]
        self.Q = self.pubkey[1]

    def getP(self):
        while True:
            x = randint(0, self.p)
            y = self.gety(x)
            if y:
                return x, y[0]
            
    def getkey(self, P):
        d = getrandbits(self.size) % self.p
        if d == 0:
            return self.getkey(P)
        Q = self.eccmul(d, P)
        common = (self.p, self.A, self.B, P)
        return (common, d), (common, Q)  # prikey, pubkey

    def pointCompress(self, P):
        return (P[0], P[1] % 2)

    def pointDecompress(self, P):
        x, r = P
        y1, y2 = self.gety(x)
        return (x, y1) if y1 % 2 == r else (x, y2)

    def crypto(self, x):
        ''' ECIES Algorithm
        @x: int, 0 < x < self.p, plaintext
        '''
        assert 0 < x < self.p, 'Encryption scope is too large!(x, p) = \
                ({}, {})'.format(x, self.p)
        k = getrandbits(self.size) % self.p
        if k == 0:
            return self.crypto(x)
        kP = self.eccmul(k, self.P)
        kQ = self.eccmul(k, self.Q)
        y1 = self.pointCompress(kP)
        y2 = x * kQ[0] % self.p
        return (y1, y2)

    def decrypt(self, y):
        assert type(y) == tuple and len(y) == 2 and \
                type(y[0]) == tuple and len(y[0]) == 2 and \
                type(y[1]) == int
        y1, y2 = y
        kP = self.pointDecompress(y1)
        kQ = self.eccmul(self.d, kP)
        x0 = kQ[0]
        x = y2 * mulinv(x0, self.p) % self.p
        return x

class ECDSA(ECC):
    def __init__(self,args=None ,q=0, a=-3, b=0, P=None, n=0, size=192):
        self.P = P
        self.d = 0
        self.n = n
        if args == None:
            b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1
            q = 0xfffffffffffffffffffffffffffffffeffffffffffffffff
            self.n = 0xffffffffffffffffffffffff99def836146bc9b1b4d22831
            super(ECDSA, self).__init__(p=q, B=b, size=size)
        elif len(args) == 2 and type(args[1]) == int:
            p, A, B, self.P, self.n = args[0]
            self.d = args[1]
            super(ECDSA, self).__init__(p=p, A=A, B=B)
        elif len(args) == 2 and len(args[1]) == 2:
            p, A, B, self.P, self.n = args[0]
            self.Q = args[1]
            super(ECDSA, self).__init__(p=p, A=A, B=B)

        if self.P == None:
            self.P = self.getP()  # be careful

    def getP(self):
        while True:
            x = randint(0, self.p)
            y = self.gety(x)
            if y:
                return x, y[0]
   
    def getkey(self):
        while self.d == 0:
            self.d = getrandbits(self.size) % self.p
        self.Q = self.eccmul(self.d, self.P)
        self.common = (self.p, self.A, self.B, self.P, self.n)
        self.prikey = (self.common, self.d)  # prikey

    def sha(self, x):
        from hashlib import sha1
        sha = sha1()
        if type(x) == str:
            x = x.encode('ascii')
        sha.update(x)
        e = int(sha.hexdigest(), 16) % self.n
        return e
        
    def sign(self, x):
        self.getkey()
        k = getrandbits(self.size) % self.n
        kP = self.eccmul(k, self.P)
        r = kP[0] % self.n
        if (k & r) == 0:
            return self.sign(x)
        e = self.sha(x)
        s = (mulinv(k, self.n) * (e + self.d * r)) % self.n
        if s == 0:
            return self.sign(x)
        pubkey = (self.common, self.Q)
        return pubkey, (r, s)

    def verify(self, x, r, s):
        if not (1 <= r <= self.n -1 and 1 <= s <= self.n -1):
            return False
        e = self.sha(x)
        inv_s = mulinv(s, self.n)
        u1 = (e * inv_s) % self.n
        u2 = (r * inv_s) % self.n
        u1P = self.eccmul(u1, self.P)
        # bug: (r * inv_s % n) * Q != (r * inv_s * d % n) * P
        # debug: self.n must be carefully choose
        u2Q = self.eccmul(u2, self.Q)
        X = self.eccplus(u1P, u2Q)
        if X == (0, 0):
            return False
        v = X[0] % self.n
        return v == r

if __name__ == '__main__':
    import ipdb
    x = b'I love you'
    ss = ECDSA()
    ipdb.set_trace()
    common = ss.sign(x)
    o = ECDSA(common[0])
    r, s = common[1]
    print(o.verify(x, r, s))
    o = ECIES()
    o.init()
    y = o.crypto(100)
    print(y)
    print(o.decrypt(y))
    c = ECC(p=23, B=17, A=9)
    P = (16, 5)
    print('y^2 = x^3 + 9x + 17 mod 23, P = {}'.format(str(P)))
    for i in range(1, 10):
        print('{}P = {}'.format(i, str(c.eccmul(i, P))))

'''
y^2 = x^3 + 9x + 17 mod 23, P = (16, 5)
1P = (16, 5)
2P = (20, 20)
3P = (14, 14)
4P = (19, 20)
5P = (13, 10)
6P = (7, 3)
7P = (8, 7)
8P = (12, 17)
9P = (4, 5)
'''
2016-6-15 23:11
0
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
30
P191 页涉及到一个大数字串到内存 0x7fffffff 进制大数转换,这里用 python实现转换

#!/usr/bin/env python
# coding: utf-8
# 2016.6.17 10:00

BE2LE = lambda x:\
        ((x >> 24) & 0xff) |\
        ((x >> 16) & 0xff) << 8 |\
        ((x >> 8) & 0xff) << 16 |\
        (x&0xff) << 24

def fgint(data):
    assert type(data) is int
    _ord = 0x80000000  # 2^31
    (x, r) = divmod(data, _ord)
    rLst = [r]
    while x != 0:
        (x, r) = divmod(x, _ord)
        rLst.append(r)
    rLst.insert(0, len(rLst))
    rLst = [BE2LE(r) for r in rLst]
    rLst = [hex(r)[2:].zfill(8).upper() for r in rLst]
    return ' '.join(rLst)

if __name__ == '__main__':
    s = "322334816268407046326335149654703840583"
    print(fgint(int(s)))

输出结果
05000000 479D4F54 21A9670A 84481207 796BFB13 0F000000

与书中数据相同
Address   Hex dump                                         ASCII
02395254  05 00 00 00|47 9D 4F 54|21 A9 67 0A|84 48 12 07|    GOT!©g
„H
02395264  79 6B FB 13|0F 00 00 00|16 00 00 00|84 41 39 02| ykû      „A9
2016-6-17 10:53
0
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
31
IDEAKeyGenMe.c 密钥扩展算法存在算法不正确的问题,导致使用标准算法实现注册机的时候加密解密结果不一致

key算法基本原理:
          子密钥的生成
                IDEA共使用52个16位子密钥,由输入的128位密钥生成,算法如下:
                        • key(128bit)分成8个16位分组,并作为前8个子密钥;(unsigned)
                        • key(128bit)循环左移25位,生成新的8个子密钥;
                        python: hex(((n << 25) | (n >> 103)) & (2**128 -1))

IDEAKeyGenMe.c key function
void key(unsigned short uskey[9], unsigned short Z[7][10])
{
    unsigned short S[54];
    int i, j, r;
    for(i = 1; i<9; i++)
        S[i-1] = uskey[i];
   
    /* shifts  S[i] 内存中128bit 数据全体循环左右25位*/
    for(i=8; i<54; i++)
        {
            if((i+2)%8 == 0)            /* 14,22,30,38,46 mod 8 = 6 剩余类[6] */
                S[i] = ((S[i-7]<<9) ^ (S[i-14]>>7)) & one;    // 剩余类[7] ^ 剩余[0]
            else if((i+1)%8==0)         /* 15,23,31,39,47*/
                S[i] = ((S[i-15]<<9) ^ (S[i-14]>>7)) & one;  //剩余类[0] ^ 剩余类[1]
            else
                S[i] = ((S[i-7]<<9) ^ (S[i-6]>>7)) & one;
        }

    /* get subkeys */

        for(r = 1; r <= round + 1 ; r++)  
            for(j = 1; j < 7; j++)
                Z[j][r]=S[6 * (r - 1) + j - 1];
}

逆向分析结果
'''wiDealKey 18B
00 00 9D 63 1D EC FD 16 B5 23 8B 83 BE 26 9B D6
5F E5
'''

'''wSubkey
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 9D 63 9B D6 AD 7D FB 9A 35 59
1D E9 D2 6F DF A2 45 07 00 00 1D EC 5F E5 CA 37
6F 5A B4 F6 1C AC 58 3B 76 A4 48 BF 00 00 FD 16
2D 3A C7 BE 7D 95 2A DF BE 69 B2 38 71 B0 60 ED
00 00 B5 23 47 FA D8 3B 77 8E 1C FB F6 55 ED 6B
D7 64 C9 E2 00 00 8B 83 07 6B D6 8E 74 B0 60 EF
DE 39 73 EC D3 DA B5 AF 00 00 BE 26 4D 16 2C 0E
F4 5B B7 E8 D1 C1 83 BD AB 7C F9 A6
'''
# python code 对内存数据格式化处理
'''wSubkey 每列表示 [Z1, Z2...Z6]
['9D63', '9BD6', 'AD7D', 'FB9A', '3559', '1DE9', 'D26F', 'DFA2', '4507', '0000']
['1DEC', '5FE5', 'CA37', '6F5A', 'B4F6', '1CAC', '583B', '76A4', '48BF', '0000']
['FD16', '2D3A', 'C7BE', '7D95', '2ADF', 'BE69', 'B238', '71B0', '60ED', '0000']
['B523', '47FA', 'D83B', '778E', '1CFB', 'F655', 'ED6B', 'D764', 'C9E2', '0000']
['8B83', '076B', 'D68E', '74B0', '60EF', 'DE39', '73EC', 'D3DA', 'B5AF', '0000']
['BE26', '4D16', '2C0E', 'F45B', 'B7E8', 'D1C1', '83BD', 'AB7C', 'F9A6']
'''

正确key 值
# 正确生成 wSubkey,每行数据由前一行 ROL25 生成
'''
['9D63', '1DEC', 'FD16', 'B523', '8B83', 'BE26', '9BD6', '5FE5']
['D9FA', '2D6A', '4717', '77C', '4D37', 'ACBF', 'CB3A', 'C63B']
['D48E', '2E0E', 'F89A', '6F59', '7F96', '758C', '77B3', 'F45A']
['1DF1', '34DE', 'B2FF', '2CEB', '18EF', '67E8', 'B5A9', '1C5C']
['BD65', 'FE59', 'D631', 'DECF', 'D16B', '5238', 'B83B', 'E269']
['B3AC', '63BD', '9FA2', 'D6A4', '7170', '77C4', 'D37A', 'CBFC']
['7B3F', '45AD', '48E2', 'E0EF']

# 正确 wSubkey, 每行表示[Z1, Z2....Z6]
'''
['0x9d63', '0x1dec', '0xfd16', '0xb523', '0x8b83', '0xbe26']
['0x9bd6', '0x5fe5', '0xd9fa', '0x2d6a', '0x4717', '0x77c']
['0x4d37', '0xacbf', '0xcb3a', '0xc63b', '0xd48e', '0x2e0e']
['0xf89a', '0x6f59', '0x7f96', '0x758c', '0x77b3', '0xf45a']
['0x1df1', '0x34de', '0xb2ff', '0x2ceb', '0x18ef', '0x67e8']
['0xb5a9', '0x1c5c', '0xbd65', '0xfe59', '0xd631', '0xdecf']
['0xd16b', '0x5238', '0xb83b', '0xe269', '0xb3ac', '0x63bd']
['0x9fa2', '0xd6a4', '0x7170', '0x77c4', '0xd37a', '0xcbfc']
['0x7b3f', '0x45ad', '0x48e2', '0xe0ef']

python 代码验证
sha1_hash = '9d631decfd16b5238b83be269bd65fe5649367c5' # hash for 'ipediy'
n = int(m.hexdigest()[0: 32], 16) #取hash值前16字节,共128bit 来做ROL25循环移位操作
assert hex(((n << 25) | (n >> 103)) & (2**128 -1)) == '0xd9fa2d6a4717077c4d37acbfcb3ac63b'
# 验证结果 key 算法不正确
2016-6-28 11:04
0
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
32
# 注册机实现遇到的问题:key扩展算法中, 16位数据 BE LE 转换问题
s2 = 0x16FD
s1 = 0xEC1D
assert ((s1 << 9) ^ (s2 >> 7)) & 0xFFFF == 0x3A2D
# 0019F260  2D 3A                                            -:

# 实际值应为
s2 = 0xFD16
s1 = 0x1DEC
assert ((s1 << 9) ^ (s2 >> 7)) & 0xFFFF == 0xD9FA

解决办法是引入 endian16函数

注册机源代码
#!/usr/bin/env python3
# coding: utf-8
# 2016-06-28 18:33:23

from hashlib import sha1
from ctypes import *
import cryptocommon
from ideacipher import *

def endian32(uint32):
    return  [uint32 >> (8 * (3 - i&3)) & 0xff for i in range(3, -1, -1)]

def endian16(x):
    # x -> bytes list
    lst = []
    for i in range(0, len(x), 2):
        lst.extend((x[i+1], x[i]))
    return lst

def vol(path='c:\\'):
    path_name = c_char_p(path.encode('ascii'))
    vol_name_buf =c_char_p(b'the-volume-name-buffer')
    vol_name_size=c_int(20)
    serial_num = c_long(0)
    max_comp_len = c_long(0)
    file_sys_flag = c_long(0)
    file_sys_name_buf= c_void_p(0)
    file_sys_name_size = c_long(0)
    windll.kernel32.GetVolumeInformationA(
        path_name,  # _In_opt_  LPCTSTR lpRootPathName
        vol_name_buf,  # _Out_opt_ LPTSTR  lpVolumeNameBuffer
        vol_name_size,  # _In_      DWORD   nVolumeNameSize
        byref(serial_num),  # _Out_opt_ LPDWORD lpVolumeSerialNumber
        byref(max_comp_len),  # _Out_opt_ LPDWORD lpMaximumComponentLength
        byref(file_sys_flag),  # _Out_opt_ LPDWORD lpFileSystemFlags
        file_sys_name_buf,   # _Out_opt_ LPTSTR  lpFileSystemNameBuffer
        file_sys_name_size)  # _In_      DWORD   nFileSystemNameSize
    return endian32(serial_num.value)

def get_serial(name):
    m = sha1()
    m.update(name.encode('ascii'))
    h = list(m.digest())
    volC = vol()
    c = h[-4:] + volC
    c = endian16(c)
    key = endian16(h[0: 16])
    serial = decrypt(c, key)
    return ''.join([hex(i)[2:].zfill(2) for i in serial]).upper()

def test():
    '''
    name = 'ipediy'
    serial = 'E3892679EAE3D708'
    hash = '9d631decfd16b5238b83be269bd65fe5649367c5'
    '''
    h = [0x9D, 0x63, 0x1D, 0xEC, 0xFD, 0x16, 0xB5, 0x23, 0x8B, 0x83, 0xBE, 0x26, 0x9B, 0xD6, 0x5F, 0xE5, 0x64, 0x93, 0x67, 0xC5]
    volC = vol()
    c2 = h[-4:] + volC

    # key 需要 16位 BE2LE 转换
    key = endian16(h[0: 16])
    # only for my pc
    assert c2 == [0x64, 0x93, 0x67, 0xC5, 0x0C, 0x23, 0xED, 0xBC]

    # encrypt function test, 序列号不用转换BE2LE
    test = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]
    c = encrypt(test, key, printdebug=False)  # function bug
    # 加密后的数据,需要 BE2LE 转换
    assert c == endian16([0xDC, 0x70, 0xB9, 0x9D, 0xAA, 0xD9, 0x92, 0x5E])

    # decrypt function test
    wSN =  [0xE3, 0x89, 0x26, 0x79, 0xEA, 0xE3, 0xD7, 0x08]
    c2 = endian16(c2)
    cc = decrypt(c2, key)
    assert cc == wSN

if __name__ == '__main__':
    print(get_serial('ipediy'))
2016-6-28 18:35
0
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
33
注册机python3.5 代码
#!/usr/bin/env python3
# coding: utf-8
# 2016.6.30

'''
blowfish setup from pypi
https://pypi.python.org/pypi/blowfish/0.6.1#downloads
'''

from ctypes import *
from os import urandom
from binascii import unhexlify, hexlify
import blowfish

def endian32(uint32):
    return  [uint32 >> (8 * (3 - i&3)) & 0xff for i in range(3, -1, -1)]

def vol(path='c:\\'):
    path_name = c_char_p(path.encode('ascii'))
    vol_name_buf =c_char_p(b'the-volume-name-buffer')
    vol_name_size=c_int(20)
    serial_num = c_long(0)
    max_comp_len = c_long(0)
    file_sys_flag = c_long(0)
    file_sys_name_buf= c_void_p(0)
    file_sys_name_size = c_long(0)
    windll.kernel32.GetVolumeInformationA(
        path_name,  # _In_opt_  LPCTSTR lpRootPathName
        vol_name_buf,  # _Out_opt_ LPTSTR  lpVolumeNameBuffer
        vol_name_size,  # _In_      DWORD   nVolumeNameSize
        byref(serial_num),  # _Out_opt_ LPDWORD lpVolumeSerialNumber
        byref(max_comp_len),  # _Out_opt_ LPDWORD lpMaximumComponentLength
        byref(file_sys_flag),  # _Out_opt_ LPDWORD lpFileSystemFlags
        file_sys_name_buf,   # _Out_opt_ LPTSTR  lpFileSystemNameBuffer
        file_sys_name_size)  # _In_      DWORD   nFileSystemNameSize
    return endian32(serial_num.value)

def byte_xor(x, y):
    # x,y -> bytes list
    assert type(x) == type(y) == list
    assert len(x) == len(y)
    z = []
    for i in range(len(x)):
        z.append(x[i] ^ y[i])
    return z

def test():
    serial = '251C2FC294A937D8F573A136A0CE910E'
    key = unhexlify(serial[0: 16])
    # key -> big-endian
    cipher = blowfish.Cipher(key, byte_order="little")
    x = unhexlify(serial[16: 32]) # big-endian
    plaintext = cipher.decrypt_block(x)
    XL = list(plaintext[0: 4])
    XR = list(plaintext[4: 8])
    k1 = byte_xor(XL, XR)
    assert vol() == k1

def get_serial():
    XL = list(urandom(4))
    XR = byte_xor(XL, vol())
    x = bytes(XL) + bytes(XR)
    key = urandom(8) # key size can range(4, 56) bytes
    cipher = blowfish.Cipher(key, byte_order="little")
    ciphertext = cipher.encrypt_block(x)
    serial = hexlify(key) + hexlify(ciphertext)
    return serial.decode('ascii').upper()

if __name__ == '__main__':
#    import ipdb
#    ipdb.set_trace()
    while True:
        print(get_serial())
        input()

----------------------------------------------------
python辅助 逆向分析过程
# 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)

################################
serial = '0123456789abcdef0123456789abcdef'
assert len(serial) == 32

from binascii import unhexlify
xSeri = list(unhexlify(serial))
# 01 23 45 67 89 AB CD EF 01 23 45 67 89 AB CD EF

key = xSeri[0: 8]
ctx = []
# ctx = BlowFish_init(key)
# ctx[0: 72] -> [P1, P18]; ctx[72: 4168] -> S-box
ctx = [0x03, 0x8D, 0x55, 0x02, 0x5B, 0xE0, 0xD2, 0x8B, 0xEA, 0x00, 0x0C, 0xE6, 0xEF, 0x70, 0xC2, 0x95, 0x55, 0x75, 0x3C, 0xF0, 0xC4, 0x57, 0xBA, 0x58, 0x41, 0x1A, 0x21, 0xA6, 0x6E, 0x51, 0x31, 0xE7, 0xC7,
....
0x18, 0x8A, 0x50, 0x53, 0x79, 0xA1, 0x36, 0x31, 0x4F, 0x06, 0x3A, 0x6E, 0xE4, 0xB3]

XL = xSeri[8: 12]
XR = xSeri[12: 16]
XL, XR = BlowFish_decrypt(ctx, XL, XR)
assert XL == [0x20, 0xDE, 0x87, 0x7D]
assert XR == [0xAB, 0x1F, 0x7A, 0x0E]

k1 = xor(XL, XR)
assert k1 == list(reversed([0x73, 0xFD, 0xC1, 0x8B]))
volC = GetVolumeInformationA(r"c:\\")
assert volC == [0x0C, 0x23, 0xED, 0xBC]

# 验证
assert k1 == volC
2016-6-30 20:44
0
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
34
学习《C语言程序设计》 花约 200小时,为进一步逆向学习打基础
2016-9-28 10:11
0
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
35
国庆结束,继续逆向学习,开始“第4篇 语言和平台篇”学习了,本来犹豫要不要学下 Delphi 再开始,加密与解密没有提到,暂且不学,以下是一点学习方法。

Delphi 反汇编方法梳理:
1.使用DeDe 定位需要逆向的代码
2.使用 IDA + DeDe 进行静态分析
3.使用 OD 进行动态分析
4.逆向分析时,使用 py 代码实时梳理代码逻辑

#!/usr/bin/env python3
# coding: utf-8
# 2016-10-08 17:17:02
# p196 ch07 DE_Delphi_6.exe

def register(name, serial):
    assert name != ''
    assert len(name) >= 4
    hex_name = ''
    for i in name:
        hex_name += hex(ord(i))[2:]

    if serial == hex_name:
        print('Success!')
    else:
        print('Error!')

def gen_serial(name):
    return ''.join([hex(ord(i))[2:] for i in name])

if __name__ == '__main__':
    name = input('name: ').strip()
    serial = input('serial: ').strip()
    register('ipediy', '1234')
    print(gen_serial('ipediy'))
2016-10-8 17:22
0
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
36
VB P-code 分析工具:x64dbg + WKTVBDE
P-code 分析遇到的问题: 40E416  DivVar var_BC  伪指令除法运算一开始未能理解逻辑,导致浪费大量时间,除法指令分析如下:
x32dbg 下断点: bph 40E416, rw ;breakpoint hardware
F9 运行,来到断点处,跟踪分析
DivVar var_BC 除法运算
741BDEE5 | mov al,byte ptr ds:[esi]                | 0xFB
741BDEE7 | inc esi                                 |
741BDEE8 | jmp dword ptr ds:[eax*4+741BED94]       |
741BEC87 | xor eax,eax                             | 0xBC
741BEC89 | mov al,byte ptr ds:[esi]                | 0x74
741BEC8B | inc esi                                 |
741BEC8C | jmp dword ptr ds:[eax*4+741BF194]       |
741BE0C3 | lea ebx,dword ptr ds:[<__vbaVarDiv>]    |
741BE0C9 | jmp msvbvm50.741BE0E1                   |
741BE0E1 | movsx edi,word ptr ds:[esi]             |
741BE0E4 | add edi,ebp                             |
741BE0E6 | push edi                                | 0x12->len(S1)
; stack
;;  0019F1E4  03 00 00 00 00 00 00 00 12 00 00 00 00 00 00 00  ................ ;len(S1)
;;  0019F1F4  05 00 00 00 00 00 00 00 50 45 52 54 FB 21 09 40  ........PERTû!.@ ;pi = 3.141592654
;;  0019F20C  08 00 00 00 00 00 00 00 04 22 48 00 00 00 00 00  ........."H..... ;
;;;   pointer -> u"105112101100105121"
741BE0E7 | call ebx                                | ebx:__vbaVarDiv
;   0019F1E4  05 00 00 00 00 00 00 00 8E 1B 63 C7 84 B7 5D 43  ..........cÇ.·]C  eax
;;  3.3458220933344824e+16 == 105112101100105121 / pi
741BE0E9 | push edi                                |
741BE0EA | xor eax,eax                             |

#!/usr/bin/env python3
# coding: utf-8
# 2016-10-23 23:39:10 P217 ch8.3.4 VB P-code 攻击实战

import binascii
import struct

# f('50 45 52 54 FB 21 09 40') -> (3.141592654,) 用来翻译内存中的 double 值,'<' 表示 little-endian
f = lambda data, fmt='<d': struct.unpack(fmt, binascii.unhexlify(data.replace(' ', '')))

def verify(name, serial):
    ''' VB P-code 逻辑再现
    name = cyclotron => S1 = 9912199108111116114111110
    '''
    name = name.strip()
    serial = serial.strip()
    assert name != '' and serial != '', 'Both name and serial need!'
    S1 = int(''.join([str(ord(i)) for i in name]))
    pi = 3.141592654
    while len(str(S1)) > 9:
        S1 = int(S1 / pi)
    S2 = (S1 ^ 0x30f85678) - 0xd8b3
    if len(name) == int(serial) - S2:
        print('The register is right!')
    else:
        print('Try again!')

def genSerial(name):
    name = name.strip()
    assert len(name) != 0
    S1 = int(''.join([str(ord(i)) for i in name]))
    while len(str(S1)) > 9:
        S1 = int(S1 / 3.141592654)
    S2 = (S1 ^ 0x30f85678) - 0xd8b3
    return len(name) + S2

if __name__ == '__main__':
    verify('cyclotron', '667574641')
    print(genSerial('cyclotron'))
2016-10-24 00:14
0
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
37
看到这一章,有个疑惑,.Net既然扩展了 PE结构,那么 .net1.0 .net2.0 .net3.5 .net4.6... 这么多版本,PE结构是不是扩展的都不一样?官方资料在哪里?P222页的 struct STORAGESIGNATURE结构体为什么 goog le不到,这个结构体是看雪文章作者自己逆向出来的么?

自己使用了 .Net PE, MetaData root, msdn, .net file format多种搜索尝试,最终发现CLI规范并不是Microsoft制定的。

学一样东西,最快的方法是找本书,而最权威的参考资料当然是官方说明书,如果有朋友也在学这一章,建议试试以下搜索关键字:
CLI_Ecma-335-part-i-iv

里面详细介绍了CLI的规范,及Metadata Physical Layout
2016-11-24 14:39
0
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
38
PEBrowserDbg 官方下载地址:http://www.smidgeonsoft.prohosting.com/pebrowse-pro-interactive-debugger.html
官方提供以下两个版本的动态调试工具:
    PEBrowseDbg64 Interactive.
        for Windows 7, Windows 8 and Windows 10 (all versions 64-bit only)
    PEBrowse Professional Interactive.
        for Windows 2000/XP/2003/Vista32/Windows 7

经 Win10 x64,win7 x64 , xp系统测试PEBrowse Professional Interactive 无法调试《加密与解密》9.3.1 中的32位 craceme.exe程序,光盘提供的工具也无法调试

PEBrowseDbg64 Interactive 仅支持 x64程序调试,于是考虑将 crackme.exe 变成 x64程序,以供 PEBrowseDbg64 使用,方法如下:
    dnSpy x86 反编译 crackme.exe,并保存C#源代码
    使用Visual Studio 2015,打开反编译代码项目,并修改项目属性为 (Release, x64平台),并编译生成 crackme x64.exe 版本
  然后使用PEBrowseDbg64 打开程序,完美调试

PEBrowseDbg64 首次运行需要配置环境变量,方法如下:
                        设置系统环境变量
                                _NT_SYMBOL_PATH
                                srv*C:\Symbols*http://msdl.microsoft.com/download/symbols
                                如果不设置,程序会出现以下提示
              “The environment variable _NT_SYMBOL_PATH was not found”

补充:使用PEBrowseDbg 动态调试,是很费力的事情,建议使用 PEBrowseDbg 查询方法或字串等信息,使用dnSpy 来搜索信息,并下断点,dnSpy 强大且动态调试方便。PEBrowseDbg调试,经过多次尝试后,还是不按书上的方法调试,放弃治疗。。
2016-12-2 11:30
0
雪    币: 207
活跃值: (58)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
39
这篇帖子值得收藏。
2016-12-2 13:57
0
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
40
流程混淆如下
    IL_0000:  nop
    br.s IL_0001
    IL_0002:  stloc.0
    ....
    IL_0033:  ret
    IL_0001:  ldc.i4.1
    br.s IL_0002
    ....

.\ilasm /resource=a.res /output=a.exe a.il 编译程序后程序可正常运行
dnSpy 反编译IL代码如下:(Reflector同样可正常反编译,书上说的异常已经不存在)
// tankaiha.sample1041.class1
// Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x00000250
public static void Main()
{
        int num = 1;
        if (num == 1)
        {
                Console.WriteLine("i=" + num.ToString());
        }
        else
        {
                Console.WriteLine("i modified");
        }
}

dnSpy v3.0.1, Reflector v8.4
2016-12-6 16:28
0
雪    币: 235
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
41
学习了,虽有好多不清梦。
2016-12-6 22:02
0
雪    币: 3746
活跃值: (3882)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
42
最近正在研究用py写windbg和ida的脚本。
2016-12-6 23:38
0
雪    币: 25
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
43
收藏,python
2016-12-15 16:55
0
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
44
原书信息
------------------------------
11.2.1 TEB结构
TEB,Thread Environment Block
在Win9x中称为TIB, Thread Information Block,其记录线程的重要信息,每个线程对应一个TEB结构
-------------------------------

描述:在 windows9.x 中的 SEH(Structured Exception Handling)结构化异常处理需要使用 TIB(Thread Information Block)线程信息块的 _EXCEPTION_REGISTRATION_RECORD 结构。而 TIB 结构包括在 TEB(Thread Environment Block) 结构下。

x64 win10 WinDbg x86测试:
0:000> dt ntdll32!_TEB
Symbol ntdll32!_TEB not found.
0:000> dt _NT_TIB
ntdll!_NT_TIB
   +0x000 ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x004 StackBase        : Ptr32 Void
   +0x008 StackLimit       : Ptr32 Void
   +0x00c SubSystemTib     : Ptr32 Void
   +0x010 FiberData        : Ptr32 Void
   +0x010 Version          : Uint4B
   +0x014 ArbitraryUserPointer : Ptr32 Void
   +0x018 Self             : Ptr32 _NT_TIB

win9.x WinDbg命令如下
0:000> dt _TEB
ntdll!_TEB
   +0x000 NtTib            : _NT_TIB
   +0x01c EnvironmentPointer : Ptr32 Void
   +0x020 ClientId         : _CLIENT_ID
   +0x028 ActiveRpcHandle  : Ptr32 Void
   +0x02c ThreadLocalStoragePointer : Ptr32 Void
   +0x030 ProcessEnvironmentBlock : Ptr32 _PEB
   ... ...
   ... ...
0:000> dt _NT_TIB
ntdll!_NT_TIB
   +0x000 ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x004 StackBase        : Ptr32 Void
   +0x008 StackLimit       : Ptr32 Void
   +0x00c SubSystemTib     : Ptr32 Void
   ... ...
   ... ...
0:000> dt _EXCEPTION_REGISTRATION_RECORD
ntdll!_EXCEPTION_REGISTRATION_RECORD
   +0x000 Next             : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : Ptr32 _EXCEPTION_DISPOSITION
2016-12-29 14:58
0
雪    币: 113
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
45

第13章 脱壳技术 ASLR随机地址转换 以方便做笔记

背景:有边学逆向边做笔记的习惯,这边开着Ollydbg调试代码,那边使用sublime的 (hightlight, AVR-ASM) 插件 + onenote 做汇编代码笔记,但是因为每次加载程序ImageBase 在Win10下都会变化,导致笔记中的汇编代码地址上下文不一致,于是想办法自己动手转换一下,于是有了以下代码。

#!/usr/bin/env python3
# coding: utf-8
# 2017-02-22 15:30:52

import re
import os
import sys

def aslr_addr(s, patt, old_ImageBase, new_ImageBase):
    assert isinstance(s, str) and isinstance(patt, str)
    assert isinstance(old_ImageBase, int) and isinstance(new_ImageBase, int)
    output = []
    s = s.split('\n')
    wide = '{:<%d}' %(max([len(i.split(';')[0]) for i in s]) + 2)
    for line in s:
        lst = re.findall(patt, line)
        # relocate new address
        for addr in lst:
            addr = addr.strip().replace('[', '').replace(']', '')
            new_addr = int(addr, 16) - old_ImageBase + new_ImageBase
            line = line.replace(addr, hex(new_addr)[2:].zfill(8).upper())
        # align comment
        if ';' not in line:
            line = wide.format(line) + ';'
        else:
            tmp = line.split(';')
            line = line = wide.format(tmp[0]) + ';' + tmp[1]
        output.append(line)
    return '\n'.join(output)
    
if __name__ == '__main__':
    helps = '''
    [help] $python aslr_addr.py old_ImageBase new_ImageBase data.asm
    [ eg.]  $python aslr_addr.py 0x510000 0x450000 data.asm'''
    if len(sys.argv) == 4:
        try:
            old_ImageBase = int(sys.argv[1], 16)
            new_ImageBase = int(sys.argv[2], 16)
        except:
            print(helps)
        data = open(sys.argv[3], 'r', encoding='utf-8').read()
    else:
        print(helps)
        sys.exit()
    patt_x32addr = r'(00[0-9A-Fa-f]{6}|\[[0-9A-Fa-f]{6,8}\])'
    result = aslr_addr(data, patt_x32addr, old_ImageBase, new_ImageBase)
    with open('tmp.asm', 'w', encoding='utf-8') as f:
        f.write(result)
    os.popen('tmp.asm')


data.asm 数据示例

0040D247   .  01141F        add dword ptr ds:[ebx+edi],edx   
0040D24A   .- EB 00         jmp short 0040D24C  ; jump here
0040D24C   >  66:830E FF    or word ptr ds:[esi],FFFF  
0040D250   .  83C6 02       add esi,2         
0040D253   .- E2 B4         loop short 0040D209 ;loop here


运行程序

>python aslr_addr.py 0x400000 0x510000 data.asm


输出(如果默认编辑器是sublime,会自动打开)

0051D247   .  01141F        add dword ptr ds:[ebx+edi],edx     ;
0051D24A   .- EB 00         jmp short 0051D24C                 ; jump here
0051D24C   >  66:830E FF    or word ptr ds:[esi],FFFF          ;
0051D250   .  83C6 02       add esi,2                          ;
0051D253   .- E2 B4         loop short 0051D209                ;loop here

程序会自动修正地址,然后对齐备注,现在做笔记或分析一些地址数据要方便点了


PS:新论坛做的很不错,比以前贴代码方便多了,就是好像不支持汇编代码。。

2017-2-22 15:45
0
游客
登录 | 注册 方可回帖
返回
//