MTK电话本联系人备份加密与破解

过去公司的一个同事的一台用于商务活动的手机坏了,机型为MTK6253,里面储存了所有的电话号码,不幸之万幸在于T卡有一份电话本备份。但这个备份疑似使用了加密,电话本信息中用户姓名显示为字母和数字之组合,而不是明文,这种备份只有原手机同款机型能导入使用,其他手机均无法正常导入,而原手机年代太过久远,早已经停产。最糟糕的是也找不到相关代码,无法从算法角度研究反解码算法。

 

同事碾转找到我,希望能破解电话本备份,把用户名还原为正常。破解中文加密信息其实十分麻烦,因为中文信息的流行编码非常多,常见的就有ASCII,UNICODE,GB2312,UTF8,UTF16,BIG5,GBK同时因为两个字节表示,又受高低位大小端影响,所以要破解中文加密资源难道相当大。一般情况下可以归纳为三步走,一是先根据密文猜测加密算法,解出明文汉字编码,二是根据明文判断文字编码,三是通过文字编码按照不同高低位写入新文件或者输出,如果能解出明文,就可以写出解密算法。

 

首先分析加密后的结果,都是形如:

1MgAwADQABVMfdw==|13 8 XXXXXX之类

因为所有记录都如此,观察可知,记录由竖框可分为两部分,竖框后面显示明文的电话号码,竖杠前是密文的用户名,电话号码每个字符由两个字节表示,字符串整体可以显示,因此可能意味着竖杠前后可能使用的是同一编码,但数字字母的各种编码ASC只占一个字节,另一字节是0填充。因此没办法推测原文件编码。同时观察分析可知加密的应该只有用户名。

 

接下来破解第一步,分析加密方法,DES和BASE64都能产生类似上面的密文,确切的说,BASE64不能算加密方式,但如果开发者出于某些目的打乱了编码的索引表,产生的密文也将是几乎没有办法破解的,除非获取相关的索引表,希望没有那么复杂,但这两种加密方式形成的密文长度不同,Base64是4的倍数,DES是12倍数,1MgAwADQABVMfdw==,数了密文长度后,发现17两个长度均不对应,其实DES和BASE64都可以根据需要改变,但其密文长度一般是有规律的,很难改变。17接近16,是4的倍数,因此尝试先使用BASE64突破口。

 

经过观察和思考,发现如果去掉密文中前面的数字,长度正好和BASE64可以匹配,于是使用在线BASE64工具和在线汉字编码查询工具结合分析编号,使用BASE64在线工具尝试解码字串MgAwADQABVMfdw==,获得一串乱码,考虑到汉字编码的不同和高低位的不同,使用十六进制输出,获得\x32\x00 \x30 \x00 \x34 \x00 \x05 \x53 \x1f \x77,使用编码查询得知对应的汉字是204包真,由于高低位的原因,网上大部分工具都无法直接正确解码。至此,找到规律,破解完成,密文不包括前面的数字,数字可能是分组信息,没有加密,用户名字信息使用unicode加BASE64编码。

 

找出了规律,就可以发挥软件开发人员的优势,写一个软件,一下子全破解。使用ECLIPSE,百度搜索一下JAVA代码,找一个一简单编辑器,添加上解密的思路一试,如下:


import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import sun.misc.BASE64Decoder;

public class MenuFrame {

	public static void main(String[] args) {

		final Frame frame = new Frame();

		frame.setSize(800, 800);

		frame.setLocation(100, 100);

		frame.addWindowListener(new WindowAdapter() {

			@Override
			public void windowClosing(WindowEvent e) {

				System.exit(0);

			}

		});

		final TextArea ta = new TextArea();
	
		frame.add(ta);
		
	
		// 创建菜单栏

		MenuBar mb = new MenuBar();

		// 创建菜单

		Menu file = new Menu("File");

		Menu edit = new Menu("Edit");

		// 创建菜单项

		MenuItem mi1 = new MenuItem("Open");

		// 添加打开文件功能响应

		mi1.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				FileDialog fd = new FileDialog(frame, "打开文件", FileDialog.LOAD);

				fd.setVisible(true);

				String fileName = fd.getDirectory() + fd.getFile();

				if (fileName != null)

				{

					try {

						FileInputStream fis = new FileInputStream(fileName);

						byte[] buf = new byte[10 * 1024];

						try {

							int len = fis.read(buf);

							ta.append(new String(buf, 0, len));

							fis.close();

						} catch (IOException e1) {

							e1.printStackTrace();

						}

					} catch (FileNotFoundException e1) {

						e1.printStackTrace();

					}

				}

			}

		});

		MenuItem mi2 = new MenuItem("解密");
		mi2.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent arg0) {
				// TODO Auto-generated method stub
				//System.exit(0);
				//String key = decryptBASE64("MgAwADQAfXYclw==");
				//String key = decryptBASE64("MgAwADQABVMfdw==");
				String key = decryptBASE64(ta.getText());
				byte[] kk = key.getBytes();
				for (int i = 0; i < kk.length; i +=2){
					byte[] b = new byte[2];
					b[0] = kk[i+1];
					b[1] = kk[i];
					//System.out.println("xxxxx:"+byteToChar(b)); 
					ta.append(String.valueOf((byteToChar(b))));
				}
			}

		});

		MenuItem mi3 = new MenuItem("Other Save");

		MenuItem mi4 = new MenuItem("Close");

		// 添加 关闭响应

		mi4.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent arg0) {
				// TODO Auto-generated method stub
				System.exit(0);
			}

		});

		MenuItem mi5 = new MenuItem("Cope");

		MenuItem mi6 = new MenuItem("Paste");

		file.add(mi1);

		file.add(mi2);

		file.add(mi3);

		file.add(mi4);

		edit.add(mi5);

		edit.add(mi6);

		mb.add(file);

		mb.add(edit);

		frame.setMenuBar(mb);

		frame.setVisible(true);

}
//解码BASE64
	  private static BASE64Decoder decoder = new  BASE64Decoder();// 解密  
	  public static String decryptBASE64(String outputStr) {  
	        String value = "";  
	        try {  
	            byte[] key = decoder.decodeBuffer(outputStr);  
	            value = new String(key);  
	        } catch (Exception e) {  
	        }  
	        return value;  
	    }  
//交换高低位
	    public static char byteToChar(byte[] b) {
	        char c = (char) (((b[0] & 0xFF) << 8) | (b[1] & 0xFF));
	        return c;
	    }
}

由于JAVA对环境的依赖,运行JAR需要配置相关的JDK,对于没运行过的人来说非常不方便,也可以开发一个VC解密软件,创建一个VCDIALOG程序,加入下面代码;


// bbbDlg.cpp : implementation file
//

#include "stdafx.h"
#include "bbb.h"
#include "bbbDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();
	
	// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA
	
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL
	
	// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/
// CBbbDlg dialog

CBbbDlg::CBbbDlg(CWnd* pParent /*=NULL*/)
: CDialog(CBbbDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CBbbDlg)
	m_encode = _T("");
	m_decode = _T("");
	m_cmd = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CBbbDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CBbbDlg)
	DDX_Text(pDX, IDC_EDIT1, m_encode);
	DDX_Text(pDX, IDC_EDIT2, m_decode);
	DDX_Text(pDX, IDC_EDIT3, m_cmd);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CBbbDlg, CDialog)
//{{AFX_MSG_MAP(CBbbDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
ON_BN_CLICKED(IDC_BUTTON2, OnButton2)
	ON_BN_CLICKED(IDC_BUTTON3, OnButton3)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/
// CBbbDlg message handlers

BOOL CBbbDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	
	// Add "About..." menu item to system menu.
	
	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);
	
	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}
	
	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CBbbDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CBbbDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting
		
		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
		
		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;
		
		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CBbbDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}
BYTE Decode_GetByte(char c);
char Encode_GetChar(BYTE num);

//===================================
//    Base64 解码
//===================================
BYTE Decode_GetByte(char c)
{
    if(c == '+')
        return 62;
    else if(c == '/')
        return 63;
    else if(c <= '9')
        return (BYTE)(c - '0' + 52);
    else if(c == '=')
        return 64;
    else if(c <= 'Z')
        return (BYTE)(c - 'A');
    else if(c <= 'z')
        return (BYTE)(c - 'a' + 26);
    return 64;
}

//解码
size_t Base64_Decode(char *pDest, const char *pSrc, size_t srclen)
{
    BYTE input[4];
    size_t i, index = 0;
    for(i = 0; i < srclen; i += 4)
    {
        //byte[0]
        input[0] = Decode_GetByte(pSrc[i]);
        input[1] = Decode_GetByte(pSrc[i + 1]);
        pDest[index++] = (input[0] << 2) + (input[1] >> 4);
        
        //byte[1]
        if(pSrc[i + 2] != '=')
        {
            input[2] = Decode_GetByte(pSrc[i + 2]);
            pDest[index++] = ((input[1] & 0x0f) << 4) + (input[2] >> 2);
        }

        //byte[2]
        if(pSrc[i + 3] != '=')
        {
            input[3] = Decode_GetByte(pSrc[i + 3]);
            pDest[index++] = ((input[2] & 0x03) << 6) + (input[3]);
        }            
    }

    //null-terminator
    pDest[index] = 0;
    return index;
}

//===================================
//    Base64 编码
//===================================
char Encode_GetChar(BYTE num)
{
    return 
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
        "0123456789"
        "+/="[num];
}

//编码
size_t Base64_Encode(char *pDest, const char *pSrc, size_t srclen)
{
    BYTE input[3], output[4];
    size_t i, index_src = 0, index_dest = 0;
    for(i = 0; i < srclen; i += 3)
    {
        //char [0]
        input[0] = pSrc[index_src++];
        output[0] = (BYTE)(input[0] >> 2);
        pDest[index_dest++] = Encode_GetChar(output[0]);

        //char [1]
        if(index_src < srclen)
        {
            input[1] = pSrc[index_src++];
            output[1] = (BYTE)(((input[0] & 0x03) << 4) + (input[1] >> 4));
            pDest[index_dest++] = Encode_GetChar(output[1]);
        }
        else
        {
            output[1] = (BYTE)((input[0] & 0x03) << 4);
            pDest[index_dest++] = Encode_GetChar(output[1]);
            pDest[index_dest++] = '=';
            pDest[index_dest++] = '=';
            break;
        }
        
        //char [2]
        if(index_src < srclen)
        {
            input[2] = pSrc[index_src++];
            output[2] = (BYTE)(((input[1] & 0x0f) << 2) + (input[2] >> 6));
            pDest[index_dest++] = Encode_GetChar(output[2]);
        }
        else
        {
            output[2] = (BYTE)((input[1] & 0x0f) << 2);
            pDest[index_dest++] = Encode_GetChar(output[2]);
            pDest[index_dest++] = '=';
            break;
        }

        //char [3]
        output[3] = (BYTE)(input[2] & 0x3f);
        pDest[index_dest++] = Encode_GetChar(output[3]);
    }
    //null-terminator
    pDest[index_dest] = 0;
    return index_dest;
}

wchar_t* ANSIToUnicode(const char* str, wchar_t * dest)
{
	int len = 0;
	len = strlen(str);
	int unicodeLen = ::MultiByteToWideChar( CP_ACP,
		0,
		str,
		-1,
		NULL,
		0 ); 
	wchar_t * pUnicode; 
	pUnicode = new wchar_t[unicodeLen+1]; 
	memset(pUnicode,0,(unicodeLen+1)*sizeof(wchar_t)); 
	::MultiByteToWideChar( CP_ACP,
		0,
		str,
		-1,
		(LPWSTR)pUnicode,
		unicodeLen ); 
	memcpy(dest, pUnicode, unicodeLen);
	delete pUnicode; 
	return dest; 
}
char* UnicodeToANSI( const wchar_t* str, char * dest )
{
	char*     pElementText;
	int    iTextLen;
	// wide char to multi char
	iTextLen = WideCharToMultiByte( CP_ACP,
		0,
		str,
		-1,
		NULL,
        0,
		NULL,
		NULL );
	pElementText = new char[iTextLen + 1];
	memset( ( void* )pElementText, 0, sizeof( char ) * ( iTextLen + 1 ) );
	::WideCharToMultiByte( CP_ACP,
		0,
		str,
		-1,
		pElementText,
		iTextLen,
		NULL,
		NULL );
	memcpy(dest, pElementText, iTextLen);
	delete[] pElementText;
	return dest;
}

void CBbbDlg::OnButton1() 
{
	// TODO: Add your control notification handler code here
	
	UpdateData(true);
	int len = m_encode.GetLength();
	//char * tmp = new char[(len/3)*4+((len%3)!=0)?4:0];
	//char tmp[(len/3)*4+((len%3)!=0)?4:0] = {0x00};
	char tmp[1024] = {0x00};
	//memset(tmp, 0x00, (len/3)*4+((len%3)!=0)?4:0);
	wchar_t tmp1[1024] = {0x00};
    ANSIToUnicode((char *)m_encode.GetBuffer(len), tmp1);

	Base64_Encode(tmp,(char *)tmp1,  len);
    m_decode.Format("%s", tmp);

    UpdateData(false);
	//delete []tmp;
}

void CBbbDlg::OnButton2() 
{
	// TODO: Add your control notification handler code here
	UpdateData(true);
	int len = m_decode.GetLength();
	//char tmp[(len/4)*3] = {0x00};
    char tmp[1024] = {0x00};
	

	Base64_Decode(tmp, (char *)m_decode.GetBuffer(len),  len);

	char tmp1[1024] = {0x00};
    UnicodeToANSI((wchar_t *)tmp, tmp1);

    m_encode.Format("%s", tmp1);

    UpdateData(false);
	//delete []tmp;
}
    CString runCmd(char* strCommend)  
    {  
        //  
        //通过管道技术回显cmd输出信息  
        //   
      
        SECURITY_ATTRIBUTES sa;  
        HANDLE hRead,hWrite;  
        CString strOutput;  
      
        sa.nLength = sizeof(SECURITY_ATTRIBUTES);   
        sa.lpSecurityDescriptor = NULL;  //使用系统默认的安全描述符   
        sa.bInheritHandle = TRUE;  //创建的进程继承句柄  
      
        if (!CreatePipe(&hRead,&hWrite,&sa,0))  //创建匿名管道  
        {    
            MessageBox(NULL,"CreatePipe Failed!","提示",MB_OK | MB_ICONWARNING);    
            return strOutput;  
        }  
      
        STARTUPINFO si;   
        PROCESS_INFORMATION pi;  
      
        ZeroMemory(&si,sizeof(STARTUPINFO));  
        si.cb = sizeof(STARTUPINFO);   
        GetStartupInfo(&si);   
        si.hStdError = hWrite;   
        si.hStdOutput = hWrite;  //新创建进程的标准输出连在写管道一端  
        si.wShowWindow = SW_HIDE;  //隐藏窗口   
        si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;  
      
      
        char cmdline[500];   
        sprintf(cmdline,"cmd /C %s",strCommend);  
      
        if (!CreateProcess(NULL,cmdline,NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi))  //创建子进程  
        {  
            MessageBox(NULL,"CreateProcess Failed!","提示",MB_OK | MB_ICONWARNING);    
            return strOutput;  
        }  
        CloseHandle(hWrite);  //关闭管道句柄  
      
        char buffer[4096] = {0};  
          
        DWORD bytesRead;  
      
        while (true)   
        {  
            if (ReadFile(hRead,buffer,4095,&bytesRead,NULL) == NULL)  //读取管道  
                break;  
      
            strOutput.Format("%s", buffer);  
            Sleep(100);  
        }  
        CloseHandle(hRead);  
      
        return strOutput;  
    }  
void CBbbDlg::OnButton3() 
{
	// TODO: Add your control notification handler code here
	UpdateData(true);
	m_cmd = runCmd("adb");
	UpdateData(false);
}


 


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值