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

xiaoxiao2021-02-28  80

过去公司的一个同事的一台用于商务活动的手机坏了,机型为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); }

 

转载请注明原文地址: https://www.6miu.com/read-77842.html

最新回复(0)