如何为便携可执行程序添加MAC地址验证并生成单可执行文件
Alright, let's break down how to add MAC address validation to your portable executable so it only runs on devices with a specific MAC address. The goal is: on startup, check if any of the device's network adapters match your target MAC—if yes, run the program normally; if not, exit immediately. Here's a step-by-step approach that keeps everything in a single EXE file:
Core Concept
The program will:
- Retrieve all network adapter MAC addresses on the local machine when it starts.
- Compare each retrieved MAC against your pre-specified target MAC.
- If a match is found, proceed with the original program logic.
- If no matches are found, display a message (optional) and exit immediately.
Practical Implementation (C/C++ for Windows)
C/C++ is ideal here because it compiles to a standalone EXE with no external dependencies. If you're modifying an existing program, you can insert this validation logic at the very start of your main function (or WinMain for GUI apps).
Step 1: Code to Fetch MAC Addresses
Use Windows' GetAdaptersAddresses API (the modern replacement for GetAdaptersInfo) to get all adapter details, including MAC addresses. Here's a reusable function:
#include <windows.h> #include <iphlpapi.h> #include <stdio.h> #include <stdlib.h> #include <string.h> // Link against iphlpapi.lib #pragma comment(lib, "iphlpapi.lib") // Convert MAC byte array to human-readable string (e.g., "00-1A-2B-3C-4D-5E") void MacToString(BYTE* mac, char* output) { sprintf(output, "%02X-%02X-%02X-%02X-%02X-%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } // Check if any adapter's MAC matches the target int IsTargetMacPresent(const char* targetMac) { PIP_ADAPTER_ADDRESSES pAddresses = NULL; ULONG outBufLen = 0; DWORD retVal; // First call to get the required buffer size retVal = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &outBufLen); if (retVal == ERROR_BUFFER_OVERFLOW) { pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen); if (!pAddresses) { printf("Memory allocation failed\n"); return 0; } // Second call to get actual adapter data retVal = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &outBufLen); } if (retVal == NO_ERROR) { PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses; char currentMac[18]; // Holds formatted MAC string while (pCurrAddresses) { if (pCurrAddresses->PhysicalAddressLength == 6) { // Valid MAC length MacToString(pCurrAddresses->PhysicalAddress, currentMac); // Compare (case-insensitive) if (_stricmp(currentMac, targetMac) == 0) { free(pAddresses); return 1; // Match found } } pCurrAddresses = pCurrAddresses->Next; } } else { printf("GetAdaptersAddresses failed: %d\n", retVal); } if (pAddresses) free(pAddresses); return 0; // No match found }
Step 2: Add Validation to Your Program
Insert this check at the very beginning of your entry point. For a console app:
int main() { const char* TARGET_MAC = "00-1A-2B-3C-4D-5E"; // Replace with your target MAC // Validate MAC first if (!IsTargetMacPresent(TARGET_MAC)) { printf("Invalid device. Exiting...\n"); exit(EXIT_FAILURE); } // Your original program logic starts here printf("MAC validated. Running program...\n"); // ... rest of your code ... return 0; }
For a GUI app (using WinMain), replace the printf with a message box and exit:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { const char* TARGET_MAC = "00-1A-2B-3C-4D-5E"; if (!IsTargetMacPresent(TARGET_MAC)) { MessageBox(NULL, L"Invalid device. Program will exit.", L"Error", MB_OK | MB_ICONERROR); return 0; } // Your GUI app logic here MessageBox(NULL, L"MAC validated. Program running.", L"Success", MB_OK); return 0; }
Compile to Single EXE
- Using MSVC: Open Developer Command Prompt, run:
cl your_program.cpp iphlpapi.lib /Fe:your_program.exe - Using MinGW: Run:
g++ your_program.cpp -o your_program.exe -liphlpapi
Both commands will produce a standalone EXE with no external dependencies.
Key Notes
- MAC Format: Ensure your target MAC uses hyphens (
-) and uppercase letters (or modify theMacToStringfunction to match your preferred format, e.g., colons:). The_stricmpmakes the comparison case-insensitive. - Multiple Adapters: The code checks all network adapters (Ethernet, Wi-Fi, Bluetooth, etc.)—so if any adapter matches, the program runs.
- MAC Spoofing: Keep in mind that MAC addresses can be spoofed, so this is a basic validation method, not a secure anti-piracy solution.
- Existing EXEs: If you can't modify the source code of your existing EXE, you'd need to use reverse engineering tools to inject the validation logic—but this is more complex and may violate software licensing terms. It's always better to add the code at the source level if possible.
内容的提问来源于stack exchange,提问作者Mahmoud Dabash

