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);
}


 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章