在接大厂MSDK的时候,因为签名的问题,影响了接SDK登录的进程,为了避免这个错误和重复操作:打开cmd输入命令来查看keystore的签名和apk和签名以及包名,因此写了个简单工具。之前有学过Windows API,但也只是用来学习DirectX,简单了解一下创建窗口流程和消息机制。界面那是什么?不了解。不想用MFC,主要是没装,网上搜索了解了下,实现了2个界面:对话框模式和纯代码模式。
1. 对话框模式
2. 纯代码模式
果然纯代码模式符合程序美。
代码其实很简单,就懒的注释了,核心就是利用cmd命令来获取结果,然后截取想要的字符串就OK了。用到了2个exe文件,一个是在android-sdk\build-tools\28.0.1\中的aapt.exe,另一个则是JDK\bin\中的keytool.exe。有一个坑是配置好环境变量后,需要关闭IDE,cmd命令才执行成功。
代码:
#define WIN32_LEAN_AND_MEAN
#define APP_NAME TEXT("GetCertificate")
#define APP_WIDTH 600
#define APP_HEIGHT 480
#define IDBUTTON_KEYSTORE 1001
#define IDBUTTON_APK 1002
#define IDBUTTON_COMMAND 1003
#define IDEDIT_KEYSTORE 2001
#define IDEDIT_KEYSTOREPASSWORD 2002
#define IDEDIT_APK 2003
#define IDEDIT_RESULT 2004
#include <Windows.h>
#include "resource.h"
#include <commdlg.h>
#include <iostream>
#include <fstream>
#pragma region Global Variables
HINSTANCE g_hInstance;
bool bUseResource = true;//是否使用对话框
HWND hEditKeystorePath;
HWND hEditKeystorePassword;
HWND hEditApkPath;
HWND hEditResult;
HWND hDialog;
#pragma endregion
#pragma region Declaration: Create UI
bool CreateUI(HWND hwnd);
bool CreateCustomDialog(HWND hwnd);
bool CreateCustomCodeView(HWND hwnd);
#pragma endregion
#pragma region Declaration: UI Event
void OnBtnKeystoreClick();
void OnBtnApkClick();
void OnBtnCommandClick();
#pragma endregion
#pragma region Declaration: Get Need Variables
bool GetKeystprepath(char* path, int length);
bool GetPassword(char* password, int length);
bool GetApkPath(char* path, int length);
#pragma endregion
#pragma region Declaration: Get Result
void GetKeystoreResult(const char* path, char* password, char* result, int length);
void GetApkResult(const char* path, char* result, int length);
void GetApkPackageName(const char* path, char* result, int length);
#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(WHITE_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)
{
bool result = false;
if (bUseResource)
result = CreateCustomDialog(hwnd);
else
result = CreateCustomCodeView(hwnd);
return result;
}
bool CreateCustomDialog(HWND hwnd)
{
hDialog = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_MAIN), hwnd, (DLGPROC)DlgProc);
if (!hDialog)
{
MessageBox(NULL, TEXT("CreateDialog function - failed"), TEXT("Error"), MB_OK | MB_ICONERROR);
return false;
}
ShowWindow(hDialog, SW_SHOW);
return true;
}
bool CreateCustomCodeView(HWND hwnd)
{
HWND hStaticKeystore = CreateWindow(
TEXT("Static"),
TEXT("Keystore证书:"),
WS_VISIBLE | WS_CHILD | SS_RIGHT | SS_SIMPLE,
20, 20,
120, 20,
hwnd,
NULL,
g_hInstance,
nullptr);
if (!hStaticKeystore)
return false;
hEditKeystorePath = CreateWindow(
TEXT("Edit"),
nullptr,
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL,
140, 20,
310, 20,
hwnd,
(HMENU)IDEDIT_KEYSTORE,
g_hInstance,
nullptr);
if (!hEditKeystorePath)
return false;
HWND hBtnKeystore = CreateWindow(
TEXT("Button"),
TEXT("打开文件"),
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
470, 20,
70, 20,
hwnd,
(HMENU)IDBUTTON_KEYSTORE,
g_hInstance,
nullptr);
if (!hBtnKeystore)
return false;
HWND hStaticKeystorePassword = CreateWindow(
TEXT("Static"),
TEXT("Keystore密码:"),
WS_VISIBLE | WS_CHILD | SS_RIGHT | SS_SIMPLE,
20, 60,
120, 20,
hwnd,
NULL,
g_hInstance,
nullptr);
if (!hStaticKeystorePassword)
return false;
hEditKeystorePassword = CreateWindow(
TEXT("Edit"),
nullptr,
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_PASSWORD | ES_AUTOHSCROLL,
140, 60,
310, 20,
hwnd,
(HMENU)IDEDIT_KEYSTOREPASSWORD,
g_hInstance,
nullptr);
if (!hEditKeystorePassword)
return false;
HWND hStaticApk = CreateWindow(
TEXT("Static"),
TEXT("APK文件:"),
WS_VISIBLE | WS_CHILD | SS_RIGHT | SS_SIMPLE,
20, 100,
120, 20,
hwnd,
NULL,
g_hInstance,
nullptr);
if (!hStaticApk)
return false;
hEditApkPath = CreateWindow(
TEXT("Edit"),
nullptr,
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL,
140, 100,
310, 20,
hwnd,
(HMENU)IDEDIT_APK,
g_hInstance,
nullptr);
if (!hEditApkPath)
return false;
HWND hBtnApk = CreateWindow(
TEXT("Button"),
TEXT("打开文件"),
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
470, 100,
70, 20,
hwnd,
(HMENU)IDBUTTON_APK,
g_hInstance,
nullptr);
if (!hBtnApk)
return false;
HWND hBtnCommand = CreateWindow(
TEXT("Button"),
TEXT("执行"),
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
300 - 35, 150,
70, 20,
hwnd,
(HMENU)IDBUTTON_COMMAND,
g_hInstance,
nullptr);
if (!hBtnCommand)
return false;
HWND hStaticResult = CreateWindow(
TEXT("Static"),
TEXT("结果:"),
WS_VISIBLE | WS_CHILD | SS_RIGHT | SS_SIMPLE,
10, 170,
120, 20,
hwnd,
NULL,
g_hInstance,
nullptr);
if (!hStaticResult)
return false;
hEditResult = CreateWindow(
TEXT("Edit"),
nullptr,
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_READONLY | ES_AUTOVSCROLL | ES_MULTILINE,
10, 200,
APP_WIDTH - 35, APP_HEIGHT - 40 - 200,
hwnd,
(HMENU)IDEDIT_RESULT,
g_hInstance,
nullptr);
if (!hEditResult)
return false;
return true;
}
#pragma endregion
#pragma region Implementation: UI Event
void OnBtnKeystoreClick()
{
char keystorePath[MAX_PATH] = { 0 };
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.lpstrFilter = TEXT("keystore Files (*.keystore)\0*.keystore\0All Files (*.*)\0*.*\0");
ofn.lpstrFile = keystorePath;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = TEXT("keystore"); //默认的打开的文件类型
ofn.lpstrInitialDir = TEXT(".\\"); //默认的打开的文件路径,这里以当前目录为例
if (GetOpenFileName(&ofn))
{
if (bUseResource)
{
if (hDialog != NULL)
{
HWND hTempEditKeystore = GetDlgItem(hDialog, IDC_KEYSTORE_FILE_PATH);
SetWindowText(hTempEditKeystore, keystorePath);
}
}
else
SetWindowText(hEditKeystorePath, keystorePath);
}
}
void OnBtnApkClick()
{
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 (bUseResource)
{
if (hDialog != NULL)
{
HWND hTempEditApk = GetDlgItem(hDialog, IDC_APK_FILE_PATH);
SetWindowText(hTempEditApk, apkPath);
}
}
else
SetWindowText(hEditApkPath, apkPath);
}
}
void OnBtnCommandClick()
{
char keystorePath[MAX_PATH] = { 0 };
char keystorePassword[MAX_PATH] = { 0 };
char apkPath[MAX_PATH] = { 0 };
bool bIsKeystorepathCorrect = GetKeystprepath(keystorePath, MAX_PATH);
bool bIsPasswordCorrect = false;
if (bIsKeystorepathCorrect)
{
bIsPasswordCorrect = GetPassword(keystorePassword, MAX_PATH);
}
bool bIsApkpathCorrect = GetApkPath(apkPath, MAX_PATH);
char keystoreMD5[MAX_PATH] = { 0 };
char apkMD5[MAX_PATH] = { 0 };
char apkPackageName[MAX_PATH] = { 0 };
char result[MAX_PATH] = { 0 };
if (bIsKeystorepathCorrect && bIsPasswordCorrect)
{
GetKeystoreResult(keystorePath, keystorePassword, keystoreMD5, MAX_PATH);
if (keystoreMD5[0] != '\0')
{
char descStr[] = "Ketstore MD5: [";
strcpy_s(result, strlen(descStr) + 1, descStr);
strcat_s(result, strlen(result) + strlen(keystoreMD5) + 1, keystoreMD5);
strcat_s(result, strlen(result) + strlen("]") + 1, "]");
}
}
if (bIsApkpathCorrect)
{
GetApkResult(apkPath, apkMD5, MAX_PATH);
GetApkPackageName(apkPath, apkPackageName, MAX_PATH);
if (apkMD5[0] != '\0')
{
if (keystoreMD5[0] != '\0')
{
char descStr[] = "\r\nAPK MD5: [";//\r\n 换行
strcat_s(result, strlen(result) + strlen(descStr) + 1, descStr);
}
else
{
char descStr[] = "APK MD5: [";
strcpy_s(result, strlen(descStr) + 1, descStr);
}
strcat_s(result, strlen(result) + strlen(apkMD5) + 1, apkMD5);
strcat_s(result, strlen(result) + strlen("]") + 1, "]");
char descStr[] = "\r\nAPK PackageName: [";
strcat_s(result, strlen(result) + strlen(descStr) + 1, descStr);
strcat_s(result, strlen(result) + strlen(apkPackageName) + 1, apkPackageName);
strcat_s(result, strlen(result) + strlen("]") + 1, "]");
if (keystoreMD5[0] != '\0')
{
if (strcmp(keystoreMD5, apkMD5) != 0)
{
char descStr[] = "\r\nKetstore MD5 和APK MD5不一致";
strcat_s(result, strlen(result) + strlen(descStr) + 1, descStr);
}
else
{
char descStr[] = "\r\nKetstore MD5 和APK MD5一致";
strcat_s(result, strlen(result) + strlen(descStr) + 1, descStr);
}
}
}
}
if (bUseResource)
{
if (hDialog != NULL)
{
HWND hTempEditResult = GetDlgItem(hDialog, IDC_RESULT);
SetWindowText(hTempEditResult, result);
}
}
else
SetWindowText(hEditResult, result);
}
#pragma endregion
#pragma region Implementation: Get Need Variables
bool GetKeystprepath(char* path, int length)
{
if (bUseResource)
{
if (hDialog != NULL)
{
HWND hTempEditKeystorePath = GetDlgItem(hDialog, IDC_KEYSTORE_FILE_PATH);
GetWindowText(hTempEditKeystorePath, path, MAX_PATH);
}
}else
GetWindowText(hEditKeystorePath, path, MAX_PATH);
if ('\0' == path[0])
return false;
char extensionName[MAX_PATH] = { 0 };
_splitpath_s(path, nullptr, 0, nullptr, 0, nullptr, 0, extensionName, MAX_PATH);
if (strcmp(extensionName, ".keystore") != 0)
{
TCHAR errorMessage[MAX_PATH] = { 0 };
wsprintf(errorMessage, TEXT("文件不是keystore文件: %s"), path);
MessageBox(NULL, errorMessage, TEXT("Error"), MB_OK | MB_ICONERROR);
return false;
}
std::ifstream tempFile(path, std::ios::binary);
if (!tempFile)
{
TCHAR errorMessage[MAX_PATH] = { 0 };
wsprintf(errorMessage, TEXT("文件不存在: %s"), path);
MessageBox(NULL, errorMessage, TEXT("Error"), MB_OK | MB_ICONERROR);
return false;
}
tempFile.close();
return true;
}
bool GetPassword(char* password, int length)
{
if (bUseResource)
{
if (hDialog != NULL)
{
HWND hTempEditKeystorePassword = GetDlgItem(hDialog, IDC_KEYSTORE_PASSWORD_INPUT);
GetWindowText(hTempEditKeystorePassword, password, MAX_PATH);
}
}
else
GetWindowText(hEditKeystorePassword, password, MAX_PATH);
if ('\0' == password[0])
{
MessageBox(NULL, TEXT("请输入密码!"), TEXT("Error"), MB_OK);
return false;
}
return true;
}
bool GetApkPath(char* path, int length)
{
if (bUseResource)
{
if (hDialog != NULL)
{
HWND hTempEditApkPath = GetDlgItem(hDialog, IDC_APK_FILE_PATH);
GetWindowText(hTempEditApkPath, path, MAX_PATH);
}
}
else
GetWindowText(hEditApkPath, path, MAX_PATH);
if ('\0' == path[0])
return false;
char extensionName[MAX_PATH] = { 0 };
_splitpath_s(path, nullptr, 0, nullptr, 0, nullptr, 0, extensionName, MAX_PATH);
if (strcmp(extensionName, ".apk") != 0)
{
TCHAR errorMessage[MAX_PATH] = { 0 };
wsprintf(errorMessage, TEXT("文件不是apk文件: %s"), path);
MessageBox(NULL, errorMessage, TEXT("Error"), MB_OK | MB_ICONERROR);
return false;
}
std::ifstream tempFile(path, std::ios::binary);
if (!tempFile)
{
TCHAR errorMessage[MAX_PATH] = { 0 };
wsprintf(errorMessage, TEXT("文件不存在: %s"), path);
MessageBox(NULL, errorMessage, TEXT("Error"), MB_OK | MB_ICONERROR);
return false;
}
tempFile.close();
return true;
}
#pragma endregion
#pragma region Declaration: Get Result
void GetKeystoreResult(const char* path, char* password, char* result, int length)
{
char commandStr[MAX_PATH] = { 0 };
char autoCommand[] = "echo ";
char keystoreCommand[] = "keytool -list -v -keystore \"";
// Auto input password
strcpy_s(commandStr, strlen(autoCommand) + 1, autoCommand);
strcat_s(commandStr, strlen(commandStr) + strlen(password) + 1, password);
strcat_s(commandStr, strlen(commandStr) + strlen("|") + 1, "|");
// Get the MD5 of the keystore
strcat_s(commandStr, strlen(commandStr) + strlen(keystoreCommand) + 1, keystoreCommand);
strcat_s(commandStr, strlen(commandStr) + strlen(path) + 1, path);
strcat_s(commandStr, strlen(commandStr) + strlen("\"") + 1, "\"");
FILE* file = _popen(commandStr, "r");
if (file != nullptr)
{
char temp[MAX_PATH] = { 0 };
char* tempResult = fgets(temp, MAX_PATH, file);
char findStr[] = "MD5: ";
while (tempResult != nullptr)
{
char* md5 = strstr(temp, findStr);
if (md5 != nullptr)
{
strncpy_s(result, length, md5 + strlen(findStr), strlen(md5) - strlen(findStr) - 1);
break;
}
else
tempResult = fgets(temp, MAX_PATH, file);
}
_pclose(file);
}
}
void GetApkResult(const char* path, char* result, int length)
{
char commandStr[MAX_PATH] = { 0 };
char command[] = "keytool -printcert -jarfile \"";
strcpy_s(commandStr, strlen(command) + 1, command);
strcat_s(commandStr, strlen(commandStr) + strlen(path) + 1, path);
strcat_s(commandStr, strlen(commandStr) + strlen("\"") + 1, "\"");
FILE* file = _popen(commandStr, "r");
if (file != nullptr)
{
char temp[MAX_PATH] = { 0 };
char* tempResult = fgets(temp, MAX_PATH, file);
char findStr[] = "MD5: ";
while (tempResult != nullptr)
{
char* md5 = strstr(temp, findStr);
if (md5 != nullptr)
{
strncpy_s(result, length, md5 + strlen(findStr), strlen(md5) - strlen(findStr) - 1);
break;
}else
tempResult = fgets(temp, MAX_PATH, file);
}
_pclose(file);
}
}
void GetApkPackageName(const char* path, char* result, int length)
{
char commandStr[MAX_PATH] = { 0 };
char command[] = "aapt dump badging \"";
strcpy_s(commandStr, strlen(command) + 1, command);
strcat_s(commandStr, strlen(commandStr) + strlen(path) + 1, path);
strcat_s(commandStr, strlen(commandStr) + strlen("\"") + 1, "\"");
FILE* file = _popen(commandStr, "r");
if (file != nullptr)
{
char temp[MAX_PATH] = { 0 };
char* tempResult = fgets(temp, MAX_PATH, file);
char findStr[] = "package: name=";
while (tempResult != nullptr)
{
char* packageName = strstr(temp, findStr);//package: name='com.zp.test' versionCode='1' versionName='1.0'
if (packageName != nullptr)
{
char* nextStr = strstr(packageName + strlen(findStr) + 1, "'");
strncpy_s(result, length, packageName + strlen(findStr) + 1, strlen(packageName) - strlen(nextStr) - strlen(findStr) - 1);
break;
}
else
tempResult = fgets(temp, MAX_PATH, file);
}
_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;
case WM_COMMAND:
{
switch (wParam)
{
case IDBUTTON_KEYSTORE:
OnBtnKeystoreClick();
break;
case IDBUTTON_APK:
OnBtnApkClick();
break;
case IDBUTTON_COMMAND:
OnBtnCommandClick();
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_KEYSTORE_FILE_PATH:
OnBtnKeystoreClick();
break;
case IDC_BUTTON_APK_FILE_PATH:
OnBtnApkClick();
break;
case IDC_BUTTON_COMMAND:
OnBtnCommandClick();
break;
}
}
break;
}
return 0;
}
#pragma endregion
参考文章: