记一次有意义二进制可执行文件的逆向分析

声明:本研究只作为个人兴趣,绝没用于商业用途。读者阅读后所用于的其他应用本人概不负责!

1、背景

        公司一直在做天网监控的项目,需要将监控摄像头的rtsp转成h264封装的实时视频,然后在电视端通过H5播放,平台是浪潮7585的高清机顶盒和其他几个厂家的安卓机顶盒,但都统一了标准。但是推流转码用的程序是厂家安装的,哪个厂家就不说了,启动时需要一个19的数字作为license,为了个人兴趣,所以研究了程序的license认证算法。

2、思路和准备

2.1 愚蠢的想法

    首先既然需要一个19位的license作为授权码,那我用程序去跑就行了,每遍历一次就去启动转码程序,检测到程序启动成功了,那么肯定就是这个数字,然后写入到文件里,,于是我跑的程序都写好了,如下:

#coding:utf-8
import time
import commands
#import subprocess
def AddStr(s):
	if(len(str(s))==1):
		s='0000'+str(s)
	elif(len(str(s))==2):
		s='000'+str(s)
	elif(len(str(s))==3):
		s='00'+str(s)
	elif(len(str(s))==4):
		s='0'+str(s)
	elif(len(str(s))==5):
		s=str(s)
	return s
	#print(type(s))
for i in range(0,9999):
	for m in range(0,99999):
		for n in range(0,99999):
			for j in range(0,99999):
				#i
				if(len(str(i))==1):
					i='000'+str(i)
				elif(len(str(i))==2):
					i='00'+str(i)
				elif(len(str(i))==3):
					i='0'+str(i)
				#print(type(i))
				#m
				AddStr(m)
				#n
				AddStr(n)
				#j
				AddStr(j)
				MyStr=str(i)+AddStr(m)+AddStr(n)+AddStr(j)
				with open('monitor_license','w+') as f:
					f.write(MyStr+'\n')
				status,output = commands.getstatusoutput('./Sdgd_Monitor')
				if 'Monitor Server Running...' in output:
					with open('license.txt','w+') as f:
						f.write(MyStr)
						exit('已成功获取license')

跑了大约两天我发现我做了一个很愚蠢的事情,假如1毫秒尝试一次,那么需要9999999999999999999/1000秒/3600/24/365=31709791.983764585年,即便1纳秒运算一次,还需要317年,,那时候估计已经天荒地老了……没办法,我想到了IDA,那个神奇的反编译工具,想不如做,于是走起。。。。

2.2 思路

既然需要本地的一个授权码,那么程序执行时肯定会生成一个去和放到服务器上的对比,那么只分析生成过程的算法就可以了

2.3 代码分析

反编译后按F5查看伪代码,本人学的电子信息工程,虽然汇编是专业课,但是都还给老师了,还是看伪代码靠谱。反编译后的主要函数列表如下:

解释如下:Main:主函数,即入口函数

                 GetMainbroadSerID:获取服务器序列号的函数

                  GetLocalProgramName:检测服务器执行的程序名函数

                  GetLocalAuthorrizeCode:生成授权码的函数,这个也是主要分析的函数

                  GetAuthorizeFileCode:获得服务器上已存在的授权码,即和生成的对比的授权码,一样才执行程序

                  checkAuthorize:检查认证的函数,即对比生成的和已存在的是否一样的函数

                  str2hash:生成授权码的算法函数

主要函数伪代码如下:

2.4 执行流程分析

综合以上伪代码可以看出,程序执行时的流程如下:

1)进入main函数,传的参数是程序名字,去checkAuthorize检查认证。

2)进入到checkAuthorize后先去生成授权码,去GetLocalAuthorrizeCode。

3)进入到GetLocalAuthorrizeCode后,先获取服务器的序列号,即去GetMainbroadSerID函数

4)到GetMainbroadSerID后,用dmidecode -s system-serial-number生成的序列号写入到一个文件,然后读文件入内存,存取读到的内容后,删除文件,然后把读到的内容作为参数去str2hash执行算法。

5)重点就在str2hash算法,过程是遍历参数字符串,用33乘以无符号数h,再加上遍历的字符串的ascii码,需要注意的是h的类型,一旦超过LL类型的范围就会溢出。最终生成一个usign的LL类型数,溢出仍然需要处理,取绝对值,和求编码一个原理。

6)回到3),用程序名加下划线拼接刚生成的无符号数,再作为参数传给str2hash,最终生成的值即为要获取的license。

7)回到2),然后读取本地的以license结尾的文件名,即放在服务器上的文件名,读取后和生成的对比。

8)回到1),对比的结果一样,正常执行程序,对比不一样,报错,执行失败。

3、用程序模拟license的生成

基于以上生成流程,用python模拟生成即可,主要代码如下:

def str2hash(str0):
	h=123456789098765
	for i in str0:
		h=33*h+ord(i)
		while h>2**64-1:
			h=h-2**64
		#print(hex(h))
	if h>2**63-1:
		h=abs(h-2**64)
	return h

str2='sdgd_Monitor_'+str(str2hash(str1))
print("序列号="+str1+"\n"+"code="+str(str2hash(str2)))

遍历流程如下图:

 经测试,生成的数值可使程序成功执行。

4、总结

        本人是做网络,兼做前端出身,有时也设计后端,主要是php,参加过多次网络安全比赛,只要遇到逆向的题一般直接放弃,这次逆向分析折腾了三天,包括IDA的使用、远程调试、函数查找、代码分析等等,但总算成功了。

        其实刚开始分析时出过好多错,主要浪费在了hash函数上,没有弄清h的类型,导致生产的总不行,后来通过linux远程调试才明白hash的执行过程。

      总之,通过这次的逆向分析让我学到了好多东西,也为以后的学习工作带来了很大的方便。

发布了2 篇原创文章 · 获赞 14 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/l123649/article/details/104429560
今日推荐