|
[原创]Python和《加密与解密》
#!/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)) |
|
[原创]Python和《加密与解密》
#!/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() |
|
[原创]Python和《加密与解密》
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的内容覆盖了“后续代码函数返回地址”,从而达到恶意目的 ....后续代码... |
|
[原创]Python和《加密与解密》
....NA.... |
|
[原创]Python和《加密与解密》
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 |
|
[原创]Python和《加密与解密》
谢谢!我只是想尝试自己实现一下,加深对md5 c源码的理解 |
|
[原创]Python和《加密与解密》
自己用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')) |
|
[讨论]关于《加密与解密》第四版进展(2016.1.1更新)
介绍下linux平台的基础知识,方便初学选择 |
|
[原创]Python和《加密与解密》
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) |
|
[原创]Python和《加密与解密》
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!"); } |
|
[原创]X86汇编之指令格式解析
http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html |
|
[原创]X86汇编之指令格式解析
文章不错,最新的文档64-IA-32-architectures-software-developer-manual-325462.pdf,有需要建议直接去Intel官方下载,感谢你的文章,直接啃英语比较慢 |
|
|
|
[原创]Python和《加密与解密》
#!/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 **************************************************** |
|
[原创]Python和《加密与解密》
在这一章节,我发现注册机的可逆函数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; } |
|
[原创]Python和《加密与解密》
今天看到加密与解密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进制形式 |
|
[原创]Python和《加密与解密》
#!/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 |
|
[分享]IDAPython和《加密与解密》
正常学习python就行,建议利用《Python》核心编程这本书开始,一直学到面向对像章节即可,如果想了解网络通信等方面,可将此书学完,正常人要学半年左右,如果没有编程基础。 |
|
[分享]IDAPython和《加密与解密》
在这一章节,我发现注册机的可逆函数F2里,并未对表达式 k2=k2*10+code[i]-48 求逆,可是为什么呢?书写错了?去群里问了下才知道原因。 因为 charNum-48是用来字符转换数字的 单步分析 □ 核心代码 CODE:00401228 push offset String ; Name='pediy' CODE:0040122D call sub_40137E ; k1=F1('pediy') CODE:00401232 push eax ; push k1 CODE:00401233 push offset byte_40217E ; serial='1234' CODE:00401238 call sub_4013D8 ; k2=F2('1234') CODE:0040123D add esp, 4 ; balance stack CODE:00401240 pop eax ; pop k1 CODE:00401241 cmp eax, ebx ; cmp k1,k2 CODE:00401243 jz short loc_40124C ; equal jmp CODE: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; } |
操作理由
RANk
{{ user_info.golds == '' ? 0 : user_info.golds }}
雪币
{{ experience }}
课程经验
{{ score }}
学习收益
{{study_duration_fmt}}
学习时长
基本信息
荣誉称号:
{{ honorary_title }}
能力排名:
No.{{ rank_num }}
等 级:
LV{{ rank_lv-100 }}
活跃值:
在线值:
浏览人数:{{ visits }}
最近活跃:{{ last_active_time }}
注册时间:{{ user_info.create_date_jsonfmt }}
勋章
兑换勋章
证书
证书查询 >
能力值