接SDK坑的就是配置文件这些,为了防止出问题,也是为了学习,最近一直在反编译一些游戏的APK,获取AndroidManifest.xml。用到了2个jar包,一个是AXMLPrinter2.jar,另一个则是主程给我的apktool_2.3.4.jar。2个都在用,AXMLPrinter2.jar反编译后的布局很舒服,不是堆在一起,看起来不是很累,但有个问题是很多显示都是数字(比如android:screenOrientation)。
这个咋看,太累了。另一个apktool_2.3.4.jar则是全部反编译,就是反编译时候稍微比较耗时,但是内容显示较全。不嫌累的话,可以用命令行来实现,但每次拷贝命令行代码太烦,就写了个工具来实现。先列下这2个jar包的命令行:
AXMLPrinter2.jar:
java -jar E:\\ZP\\DecompileXml\\AXMLPrinter2.jar xxx.xml > xxx.xxx
E:\\ZP\\DecompileXml\\AXMLPrinter2.jar是jar包存放目录,xxx.xml是需要反编译的XML文件,xxx.xxx则是需要反编译后生成的文件,txt和xml都可以。(其他没测)
apktool_2.3.4.jar:
java -jar E:\\ZP\\DecompileXml\\apktool_2.3.4.jar d -f xxx.apk -o xxx
E:\\ZP\\DecompileXml\\apktool_2.3.4.jar是jar包存放目录,xxx.apk是需要反编译的XML文件,xxx则是需要反编译后存放的目录。
先来看下界面样式,多么符合程序美:
代码:
#define WIN32_LEAN_AND_MEAN
#define APP_NAME TEXT("DecompileXml")
#define APP_WIDTH 600
#define APP_HEIGHT 480
#include <Windows.h>
#include "resource.h"
#include <commdlg.h>
#include <ShlObj.h>
#include <iostream>
#include <fstream>
#pragma region Global Variables
HINSTANCE g_Hinstance;
HWND g_hDialog;
bool b_DecompileXml = false;
#pragma endregion
#pragma region Declaration: Create UI
bool CreateUI(HWND hwnd);
#pragma endregion
#pragma region Declaration: UI Event
void OnBtnXMLClick();
void OnBtnOutputClick();
void OnBtnCommandClick();
#pragma endregion
#pragma region Declaration: Command
void GetXMLFile();
void GetAPKFile();
void GetOutputDirectory();
void DecompileXML();
void DecompileAPK();
#pragma endregion
#pragma region Declaration: Message Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
#pragma endregion
#pragma region Main Entry
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
g_Hinstance = hInstance;
WNDCLASSEX wc;
wc.cbClsExtra = 0;
wc.cbSize = sizeof(wc);
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = wc.hIcon;
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = APP_NAME;
wc.lpszMenuName = nullptr;
wc.style = CS_HREDRAW | CS_VREDRAW;
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, TEXT("RegisterClassEx function - failed"), TEXT("Error"), MB_OK | MB_ICONERROR);
return 0;
}
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
int posX = (screenWidth - APP_WIDTH) / 2;
int posY = (screenHeight - APP_HEIGHT) / 2;
HWND hwnd = CreateWindowEx(WS_EX_APPWINDOW,
wc.lpszClassName,
wc.lpszClassName,
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU,
posX, posY,
APP_WIDTH, APP_HEIGHT,
NULL,
NULL,
hInstance,
nullptr);
if (!hwnd)
{
MessageBox(NULL, TEXT("CreateWindowEx function - failed"), TEXT("Error"), MB_OK | MB_ICONERROR);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
MSG msg;
memset(&msg, 0, sizeof(msg));
while (msg.message != WM_QUIT)
{
if (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
#pragma endregion
#pragma region Implementation: Create UI
bool CreateUI(HWND hwnd)
{
g_hDialog = CreateDialog(g_Hinstance, MAKEINTRESOURCE(IDD_DIALOG1), hwnd, (DLGPROC)DlgProc);
if (!g_hDialog)
{
MessageBox(NULL, TEXT("CreateDialog function - failed"), TEXT("Error"), MB_OK | MB_ICONERROR);
return false;
}
ShowWindow(g_hDialog, SW_SHOW);
// 设置为桌面路径
char outputDirectory[MAX_PATH] = { 0 };
SHGetSpecialFolderPath(0, outputDirectory, CSIDL_DESKTOPDIRECTORY, 0);
HWND hTempEditOutput = GetDlgItem(g_hDialog, IDC_EDIT_Output);
SetWindowText(hTempEditOutput, outputDirectory);
return true;
}
#pragma endregion
#pragma region Implementation: UI Event
void OnBtnXMLClick()
{
if(b_DecompileXml)
GetXMLFile();
else
GetAPKFile();
}
void OnBtnOutputClick()
{
GetOutputDirectory();
}
void OnBtnCommandClick()
{
if (b_DecompileXml)
DecompileXML();
else
DecompileAPK();
}
#pragma endregion
#pragma region Declaration: Command
void GetXMLFile()
{
char xmlPath[MAX_PATH] = { 0 };
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.lpstrFilter = TEXT("xml Files (*.xml)\0*.xml\0All Files (*.*)\0*.*\0");
ofn.lpstrFile = xmlPath;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = TEXT("xml"); //默认的打开的文件类型
ofn.lpstrInitialDir = TEXT(".\\"); //默认的打开的文件路径,这里以当前目录为例
if (GetOpenFileName(&ofn))
{
if (g_hDialog != NULL)
{
HWND hTempEditXml = GetDlgItem(g_hDialog, IDC_EDIT_XML);
SetWindowText(hTempEditXml, xmlPath);
}
}
}
void GetAPKFile()
{
char apkPath[MAX_PATH] = { 0 };
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.lpstrFilter = TEXT("apk Files (*.apk)\0*.apk\0All Files (*.*)\0*.*\0");
ofn.lpstrFile = apkPath;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = TEXT("apk"); //默认的打开的文件类型
ofn.lpstrInitialDir = TEXT(".\\"); //默认的打开的文件路径,这里以当前目录为例
if (GetOpenFileName(&ofn))
{
if (g_hDialog != NULL)
{
HWND hTempEditXml = GetDlgItem(g_hDialog, IDC_EDIT_XML);
SetWindowText(hTempEditXml, apkPath);
}
}
}
void GetOutputDirectory()
{
BROWSEINFO bi;
memset(&bi, 0, sizeof(bi));
bi.ulFlags = BIF_BROWSEFORCOMPUTER | BIF_EDITBOX | BIF_NEWDIALOGSTYLE;
bi.lpszTitle = "请选择反编译后文件存放目录";
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
if (!pidl) return;
char outputDirectory[MAX_PATH] = { 0 };
SHGetPathFromIDList(pidl, outputDirectory);
if ('\0' == outputDirectory[0])
MessageBox(NULL, "获取文件存放目录有误", "错误", MB_OK | MB_ICONERROR);
else
{
if (g_hDialog != NULL)
{
HWND hTempEditOutput = GetDlgItem(g_hDialog, IDC_EDIT_Output);
SetWindowText(hTempEditOutput, outputDirectory);
}
}
}
void DecompileXML()
{
if (NULL == g_hDialog) return;
char xmlPath[MAX_PATH] = { 0 };
HWND hTempEditXml = GetDlgItem(g_hDialog, IDC_EDIT_XML);
GetWindowText(hTempEditXml, xmlPath, MAX_PATH);
char outputDirectory[MAX_PATH] = { 0 };
HWND hTempEditOutput = GetDlgItem(g_hDialog, IDC_EDIT_Output);
GetWindowText(hTempEditOutput, outputDirectory, MAX_PATH);
char outputXmlPath[MAX_PATH] = { 0 };
char* findStr = strrchr(xmlPath, '\\');
++findStr;// 去掉'\\'
strcpy_s(outputXmlPath, strlen(outputDirectory) + 1, outputDirectory);
char preName[] = "\\Decompile_";
strcat_s(outputXmlPath, strlen(outputXmlPath) + strlen(preName) + 1, preName);
strcat_s(outputXmlPath, strlen(outputXmlPath) + strlen(findStr) + 1, findStr);
char commandStr[MAX_PATH] = { 0 };
char command[] = "java -jar E:\\ZP\\DecompileXml\\AXMLPrinter2.jar ";
strcpy_s(commandStr, strlen(command) + 1, command);
strcat_s(commandStr, strlen(commandStr) + strlen(xmlPath) + 1, xmlPath);
char convertStr[] = " > ";
strcat_s(commandStr, strlen(commandStr) + strlen(convertStr) + 1, convertStr);
strcat_s(commandStr, strlen(commandStr) + strlen(outputXmlPath) + 1, outputXmlPath);
FILE* file = _popen(commandStr, "r");
if (file != nullptr)
_pclose(file);
}
void DecompileAPK()
{
if (NULL == g_hDialog) return;
char apkPath[MAX_PATH] = { 0 };
HWND hTempEditXml = GetDlgItem(g_hDialog, IDC_EDIT_XML);
GetWindowText(hTempEditXml, apkPath, MAX_PATH);
char outputDirectory[MAX_PATH] = { 0 };
HWND hTempEditOutput = GetDlgItem(g_hDialog, IDC_EDIT_Output);
GetWindowText(hTempEditOutput, outputDirectory, MAX_PATH);
char outputApkPath[MAX_PATH] = { 0 };
char* findStr = strrchr(apkPath, '\\');
++findStr;// 去掉'\\'
char outputFileName[MAX_PATH] = { 0 };
strncpy_s(outputFileName, MAX_PATH, findStr, strlen(findStr) - strlen(".apk"));//获取APK name
strcpy_s(outputApkPath, strlen(outputDirectory) + 1, outputDirectory);
char preName[] = "\\Decompile_";
strcat_s(outputApkPath, strlen(outputApkPath) + strlen(preName) + 1, preName);
strcat_s(outputApkPath, strlen(outputApkPath) + strlen(outputFileName) + 1, outputFileName);
char commandStr[MAX_PATH] = { 0 };
char command[] = "java -jar E:\\ZP\\DecompileXml\\apktool_2.3.4.jar d -f ";
strcpy_s(commandStr, strlen(command) + 1, command);
strcat_s(commandStr, strlen(commandStr) + strlen(apkPath) + 1, apkPath);
char convertStr[] = " -o ";
strcat_s(commandStr, strlen(commandStr) + strlen(convertStr) + 1, convertStr);
strcat_s(commandStr, strlen(commandStr) + strlen(outputApkPath) + 1, outputApkPath);
FILE* file = _popen(commandStr, "r");
if (file != nullptr)
_pclose(file);
}
#pragma endregion
#pragma region Implementation: Message Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
bool result = CreateUI(hwnd);
if (!result)
PostQuitMessage(0);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
{
switch ((char)wParam)
{
case VK_ESCAPE:
PostQuitMessage(0);
break;
}
}
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
INT_PTR CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COMMAND:
{
switch (wParam)
{
case IDC_BUTTON_XML:
OnBtnXMLClick();
break;
case IDC_BUTTON_Output:
OnBtnOutputClick();
break;
case IDC_BUTTON_Command:
OnBtnCommandClick();
break;
}
}
break;
}
return 0;
}
#pragma endregion
代码其实很简单,就不做解释了,有兴趣的可以研究下。