C++ BaseAddress and entry point address - c++

I know that in c# I can do:
Process currentProcess = System.Diagnostics.Process.GetCurrentProcess();
currentProcess.Modules[0].BaseAddress
currentProcess.Modules[0].EntryPointAddress
How would I get this information in C++?
Taking a look I have:
void
get_module_name_for_address(LPVOID address,
TCHAR *buf, int buf_size)
{
HANDLE process;
HMODULE modules[256];
DWORD bytes_needed, num_modules;
unsigned int i;
buf[0] = '\0';
process = GetCurrentProcess();
if (EnumProcessModules(process, (HMODULE *) &modules,
sizeof(modules), &bytes_needed) == 0)
{
return;
}
if (bytes_needed > sizeof(modules))
bytes_needed = sizeof(modules);
num_modules = bytes_needed / sizeof(HMODULE);
for (i = 0; i < num_modules; i++)
{
MODULEINFO mi;
if (GetModuleInformation(process, modules[i], &mi, sizeof(mi)) != 0)
{
LPVOID start, end;
start = mi.lpBaseOfDll;
end = (char *) start + mi.SizeOfImage;
if (address >= start && address <= end)
{
GetModuleBaseName(process, modules[i], buf, buf_size);
return;
}
}
}
}

GetModuleInformation() in unmanaged code: http://msdn.microsoft.com/en-us/library/ms683201%28v=VS.85%29.aspx

Related

C++ WINAPI Shared memory dynamic arrays

I'm trying to share an array of structs containing 2 dynamic arrays using shared memory to use the structs in another process. So far I can share an array of structs but these do not contain dynamic arrays yet. Any help on completing this problem would be great.
Expected:
typedef struct {
int id;
int type;
int count;
int[] values;
int[] settings;
} Entry;
Current code:
typedef struct {
int id;
int type;
int count;
} Entry;
BOOL DumpEntries(TCHAR* memName) {
int size = entries.size() * sizeof(Entry) + sizeof(DWORD);
::hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, memName);
if (::hMapObject == NULL) {
return FALSE;
}
::vMapData = MapViewOfFile(::hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, size);
if (::vMapData == NULL) {
CloseHandle(::hMapObject);
return FALSE;
}
(*(DWORD*)::vMapData) = entries.size();
Entry* eArray = (Entry*)(((DWORD*)::vMapData) + 1);
for(int i = entries.size() - 1; i >= 0; i--) eArray[i] = entries.at(i);
UnmapViewOfFile(::vMapData);
return TRUE;
}
BOOL ReadEntries(TCHAR* memName, Entry** entries, DWORD &number_of_entries) {
HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, memName);
if (hMapFile == NULL) {
return FALSE;
}
DWORD *num_entries = (DWORD*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (num_entries == NULL) {
CloseHandle(hMapFile);
return FALSE;
}
number_of_entries = *num_entries;
if(number_of_entries == 0)
{
// special case: when no entries was found in buffer
*entries = NULL;
return true;
}
Entry* tmpEntries = (Entry*)(num_entries + 1);
*entries = new Entry[*num_entries];
for (UINT i = 0; i < *num_entries; i++) {
(*entries)[i] = tmpEntries[i];
}
UnmapViewOfFile(num_entries);
CloseHandle(hMapFile);
return TRUE;
}
You can't pass pointers across process boundaries, so you can't store pointers inside the struct items that you put in the shared memory. What you can do is allocate the shared memory block itself to be large enough to hold all of the array data, and then use offsets to access the various arrays as needed, eg:
typedef struct
{
int id;
int type;
int count;
int *values;
int *settings;
} Entry;
#pragma pack(push, 1)
typedef struct
{
int id;
int type;
int count;
DWORD values_offset;
DWORD values_count; // if different than 'int count'
DWORD settings_offset;
DWORD settings_count; // if different than 'int count'
} SharedMemEntry;
#pragma pack(pop)
BOOL DumpEntries(TCHAR* memName)
{
DWORD NumValues = 0;
DWORD NumSettings = 0;
// or whatever your container actually is...
for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
iter != entries.rend(); ++iter)
{
Entry &e = *iter;
// or whatever you have to do to calculate how many
// integers are in the values[] and settings[] arrays...
//
NumValues += e.count;
NumSettings += e.count;
}
DWORD memsize = sizeof(DWORD) +
(entries.size() * sizeof(SharedMemEntry)) +
(sizeof(int) * NumValues) +
(sizeof(int) * NumSettings);
if (hMapObject != NULL)
CloseHandle(hMapObject);
hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, memsize, memName);
if (hMapObject == NULL) {
return FALSE;
}
BYTE *vMapData = (BYTE*) MapViewOfFile(hMapObject, FILE_MAP_WRITE, 0, 0, memsize);
if (vMapData == NULL) {
CloseHandle(hMapObject);
hMapObject = NULL;
return FALSE;
}
DWORD *pEntryCount = (DWORD*) vMapData;
*pEntryCount = entries.size();
SharedMemEntry* pEntries = (SharedMemEntry*) (pEntryCount + 1);
int *pValues = (int*) (pEntries + entries.size());
int *pSettings = (int*) (pValues + NumValues);
// or whatever your container actually is...
for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
iter != entries.rend(); ++iter)
{
Entry &e = *iter;
SharedMemEntry &eEntry = *pEntries++;
eEntry.id = e.id;
eEntry.type = e.type;
eEntry.count = e.count;
eEntry.values_offset = ((BYTE*)pValues - vMapData);
eEntry.values_count = e.count; // or whatever you need...
for(DWORD k = 0; k < eEntry.values_count; ++k) {
*pValues++ = e.values[k];
}
eEntry.settings_offset = ((BYTE*)pSettings - vMapData);
eEntry.settings_count = e.count; // or whatever you need...
for(DWORD k = 0; k < eEntry.settings_count; ++k) {
*pSettings++ = e.settings[k];
}
}
UnmapViewOfFile(vMapData);
return TRUE;
}
BOOL ReadEntries(TCHAR* memName, Entry** entries, DWORD &num_entries)
{
HANDLE hMapFile = OpenFileMapping(FILE_MAP_READ, FALSE, memName);
if (hMapFile == NULL) {
return FALSE;
}
BYTE *vMapData = (BYTE*) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
if (vMapData == NULL) {
CloseHandle(hMapFile);
return FALSE;
}
DWORD *pEntryCount = (DWORD*) vMapData;
num_entries = *pEntryCount;
if (num_entries == 0)
{
// special case: when no entries was found in buffer
*entries = NULL;
}
else
{
SharedMemEntry *pEntries = (SharedMemEntry*) (pEntryCount + 1);
*entries = new Entry[num_entries];
for (DWORD i = 0; i < num_entries; ++i)
{
Entry &e = (*entries)[i];
SharedMemEntry &eEntry = pEntries[i];
e.id = eEntry.id;
e.type = eEntry.type;
e.count = eEntry.count;
e.values = new int[eEntry.values_count];
e.settings = new int[eEntry.settings_count];
int *pValues = (int*) (vMapData + eEntry.values_offset);
for(DWORD j = 0; j < eEntry.values_count; ++j) {
e.values[j] = pValues[j];
}
int *pSettings = (int*) (vMapData + eEntry.settings_offset);
for(DWORD j = 0; j < eEntry.settings_count; ++j) {
e.settings[j] = pSettings[j];
}
}
}
UnmapViewOfFile(vMapData);
CloseHandle(hMapFile);
return TRUE;
}
Alternatively, you should consider automating the memory management and loops instead of doing everything manually:
typedef struct
{
int id;
int type;
int count;
std::vector<int> values;
std::vector<int> settings;
} Entry;
#pragma pack(push, 1)
typedef struct
{
int id;
int type;
int count;
DWORD values_offset;
DWORD values_count; // if different than 'int count'
DWORD settings_offset;
DWORD settings_count; // if different than 'int count'
} SharedMemEntry;
#pragma pack(pop)
BOOL DumpEntries(TCHAR* memName)
{
DWORD NumValues = 0;
DWORD NumSettings = 0;
// or whatever your container actually is...
for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
iter != entries.rend(); ++iter)
{
Entry &e = *iter;
NumValues += e.values.size();
NumSettings += e.settings.size();
}
DWORD memsize = sizeof(DWORD) +
(entries.size() * sizeof(SharedMemEntry)) +
(sizeof(int) * NumValues) +
(sizeof(int) * NumSettings);
if (hMapObject != NULL)
CloseHandle(hMapObject);
hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, memsize, memName);
if (!hMapObject) {
return FALSE;
}
std::unique_ptr<void, decltype(&UnmapViewOfFile)> uMapData( MapViewOfFile(hMapObject, FILE_MAP_WRITE, 0, 0, memsize), &UnmapViewOfFile );
BYTE *vMapData = (BYTE*) uMapData.get();
if (!vMapData) {
CloseHandle(hMapObject);
hMapObject = NULL;
return FALSE;
}
DWORD *pEntryCount = (DWORD*) vMapData;
*pEntryCount = entries.size();
SharedMemEntry* pEntries = (SharedMemEntry*) (pEntryCount + 1);
int *pValues = (int*) (pEntries + entries.size());
int *pSettings = (int*) (pValues + NumValues);
// or whatever your container actually is...
for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
iter != entries.rend(); ++iter)
{
Entry &e = *iter;
SharedMemEntry &eEntry = *pEntries++;
eEntry.id = e.id;
eEntry.type = e.type;
eEntry.count = e.count;
eEntry.values_offset = ((BYTE*)pValues - vMapData);
eEntry.values_count = e.values.size();
pValues = std::copy(e.values.begin(), e.values.end(), pValues);
eEntry.settings_offset = ((BYTE*)pSettings - vMapData);
eEntry.settings_count = e.settings.size();
pSettings = std::copy(e.settings.begin(), e.settings.end(), pSettings);
}
return TRUE;
}
// or whatever container type you want...
BOOL ReadEntries(TCHAR* memName, std::vector<Entry> &entries)
{
entries.clear();
std::unique_ptr<std::remove_pointer<HANDLE>::type, decltype(&CloseHandle)> uMapFile( OpenFileMapping(FILE_MAP_READ, FALSE, memName), &CloseHandle );
HANDLE hMapFile = uMapFile.get();
if (!hMapFile) {
return FALSE;
}
std::unique_ptr<void, decltype(&UnmapViewOfFile)> uMapData( MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0), &UnmapViewOfFile );
BYTE *vMapData = (BYTE*) uMapData.get();
if (!vMapData) {
return FALSE;
}
DWORD *pEntryCount = (DWORD*) vMapData;
DWORD num_entries = *pEntryCount;
if (num_entries != 0)
{
entries.resize(num_entries);
SharedMemEntry *pEntries = (SharedMemEntry*) (pEntryCount + 1);
for (DWORD i = 0; i < num_entries; ++i)
{
Entry &e = entries[i];
SharedMemEntry &eEntry = pEntries[i];
e.id = eEntry.id;
e.type = eEntry.type;
e.count = eEntry.count;
e.values.reserve(eEntry.values_count);
e.settings.reserve(eEntry.settings_count);
int *pValues = (int*) (vMapData + eEntry.values_offset);
std::copy(pValues, pValues + eEntry.values_count, std::back_inserter(e.values));
int *pSettings = (int*) (vMapData + eEntry.settings_offset);
std::copy(pSettings, pSettings + eEntry.settings_count, std::back_inserter(e.settings));
}
}
return TRUE;
}
Either way, make sure you provide some kind of synchronization between DumpEntries() and ReadEntries(), such as with shared events from CreateEvent(), so that ReadEntries() does not try to read from the memory while DumpEntries() is still writing to it, and vice versa.

Fetch LAN ip addresses does not work

The codes are as follows. I want to enumerate all the ips. Part of the codes are used to my GUI, i am sure that the error has no relevance with them.
void udpchat1::getNameAndIp() {
struct hostent *host;
struct in_addr *ptr;
DWORD dwScope = RESOURCE_CONTEXT;
NETRESOURCE *NetResource = NULL;
HANDLE hEnum;
WNetOpenEnum(dwScope, NULL, NULL, NULL, &hEnum);
WSADATA wsaData;
WSAStartup(MAKEWORD(1, 1), &wsaData);
ui.IpListWidget->clear();
names.clear();
ui.chatIpLabel->setText("1111111111111");
sendAble = false;
// flag = false;
if (hEnum)
{
DWORD Count = 0xFFFFFFFF;
DWORD BufferSize = 10240;
LPVOID Buffer = new char[10240];
WNetEnumResource(hEnum, &Count, Buffer, &BufferSize);
NetResource = (NETRESOURCE*)Buffer;
char szHostName[200];
for (unsigned int i = 0; i < BufferSize / sizeof(NETRESOURCE); i++, NetResource++)
{
if (NetResource->dwUsage == RESOURCEUSAGE_CONTAINER && NetResource->dwType == RESOURCETYPE_ANY)
{
if (NetResource->lpRemoteName)
{
CString strFullName = NetResource->lpRemoteName;
if (0 == strFullName.Left(2).Compare(_T("\\\\")))
strFullName = strFullName.Right(strFullName.GetLength() - 2);
gethostname(szHostName, strlen(szHostName));
USES_CONVERSION;
char *pchar = T2A(strFullName);
host = gethostbyname(pchar);
if (host == NULL) continue;
ptr = (struct in_addr *) host->h_addr_list[0];
std::string str = "";
for (int n = 0; n < 4; n++)
{
CString addr;
if (n > 0)
{
str += ".";
}
int value = (unsigned int)((unsigned char*)host->h_addr_list[0])[n];
char p[20];
sprintf(p, "%d", value);
str.append(p);
}
names.insert(std::pair<std::string, std::string>(host->h_name, str));
ui.IpListWidget->addItem(QString::fromStdString(host->h_name));
//std::cout << "IP:" << str << " Name:" << host->h_name << std::endl;
}
}
}
delete Buffer;
WNetCloseEnum(hEnum);
}
WSACleanup();
}
I used debugging, and i found the program can not get in to this if statement.
if (NetResource->lpRemoteName)
Here is a screenshot of the debug inspector.

Image base address of foreign exe/dll or WTF?

I have a foreign process (exe-file DllProj.exe is running), that has SampleDll.dll linked to it (implicit linking). I can find the base address of the linked dll with the help of my function imageBase(), but not the base address of the process itself! What is the difference and why it's not working as is?
I mean, this code returns pBase with correct DOS/NT-headers:
LPVOID pBase = imageBase("DllProj.exe", "SampleDll.dll");
if (!pBase)
return false;
PIMAGE_DOS_HEADER pDosHeader = PIMAGE_DOS_HEADER((HMODULE)pBase);
if (::IsBadReadPtr(pDosHeader, sizeof(IMAGE_DOS_HEADER)) ||
IMAGE_DOS_SIGNATURE != pDosHeader->e_magic)
return false;
but this code return is FALSE:
LPVOID pBase = imageBase("DllProj.exe", "DllProj.exe");
//and so on...
Here is my procedure:
LPVOID imageBase(LPSTR szVictimProcess, LPSTR szVictim)
{
//находим процесс szVictimProcess
DWORD aProcesses[1024], cbNeeded, nProcesses;
unsigned int i;
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
return NULL;
nProcesses = cbNeeded / sizeof(DWORD);
HANDLE ProcHandle = 0;
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
for (i = 0; i < nProcesses; i++)
{
ProcHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, aProcesses[i]);
if (NULL != ProcHandle)
{
HMODULE hMod[1024];
if ( EnumProcessModules(ProcHandle, hMod, sizeof(hMod), &cbNeeded) )
{
GetModuleBaseName(ProcHandle, hMod[0], szProcessName, sizeof(szProcessName)/sizeof(TCHAR)); // Get the process name
if (0 == lstrcmpiA(szVictimProcess, szProcessName))
{
//находим модуль szVictim
DWORD nModules = cbNeeded / sizeof(HMODULE);
char szModName[MAX_PATH];
for (unsigned int j = 0; j < nModules; j++)
{
if (GetModuleFileNameEx(ProcHandle, hMod[j], szModName, sizeof(szModName))) // Get the module name
{
shortName(szModName);
if (0 == lstrcmpiA(szModName, szVictim))
{
MODULEINFO info;
GetModuleInformation(ProcHandle, hMod[j], &info, sizeof(info));
return info.lpBaseOfDll;
//Equal To:
//return hMod[j];
//Debug:
//LPSTR string = new char[256];
//wsprintf(string,"\t%s (0x%08X)\n", szModName, hMod[j]);
}
}
}
break;
}
}
}
CloseHandle(ProcHandle);
}
return NULL;
}
P.S.: My next goal is to get import-table of DllProj.exe (where Sample.dll is) and hiijack dll's function call
What about using this:
#pragma comment( lib, "psapi" )
DWORD GetModuleBase(HANDLE hProc, string &sModuleName)
{
HMODULE *hModules;
char szBuf[50];
DWORD cModules;
DWORD dwBase = -1;
//------
EnumProcessModules(hProc, hModules, 0, &cModules);
hModules = new HMODULE[cModules/sizeof(HMODULE)];
if(EnumProcessModules(hProc, hModules, cModules/sizeof(HMODULE), &cModules)) {
for(int i = 0; i < cModules/sizeof(HMODULE); i++) {
if(GetModuleBaseName(hProc, hModules[i], szBuf, sizeof(szBuf))) {
if(sModuleName.compare(szBuf) == 0) {
dwBase = (DWORD)hModules[i];
break;
}
}
}
}
delete[] hModules;
return dwBase;
}
Credit to answer here
There is nothing wrong with your code, I compiled your code and it works fine and outputs the correct address to console. Make sure you run as administrator. This is the project using your code which I tested working:
#include <windows.h>
#include <iostream>
#include <psapi.h>
#include <string>
void shortName(LPSTR strToChange)
{
std::string path(strToChange);
std::string filename;
size_t pos = path.find_last_of("\\");
if (pos != std::string::npos)
filename.assign(path.begin() + pos + 1, path.end());
else
filename = path;
lstrcpy(strToChange, filename.data());
}
LPVOID imageBase(LPSTR szVictimProcess, LPSTR szVictim)
{
DWORD aProcesses[1024], cbNeeded, nProcesses;
unsigned int i;
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
return NULL;
nProcesses = cbNeeded / sizeof(DWORD);
HANDLE ProcHandle = 0;
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
for (i = 0; i < nProcesses; i++)
{
ProcHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, aProcesses[i]);
if (NULL != ProcHandle)
{
HMODULE hMod[1024];
if (EnumProcessModules(ProcHandle, hMod, sizeof(hMod), &cbNeeded))
{
GetModuleBaseName(ProcHandle, hMod[0], szProcessName, sizeof(szProcessName) / sizeof(TCHAR)); // Get the process name
if (0 == lstrcmpiA(szVictimProcess, szProcessName))
{
DWORD nModules = cbNeeded / sizeof(HMODULE);
char szModName[MAX_PATH];
for (unsigned int j = 0; j < nModules; j++)
{
if (GetModuleFileNameEx(ProcHandle, hMod[j], szModName, sizeof(szModName))) // Get the module name
{
shortName(szModName);
if (0 == lstrcmpiA(szModName, szVictim))
{
MODULEINFO info;
GetModuleInformation(ProcHandle, hMod[j], &info, sizeof(info));
return info.lpBaseOfDll;
}
}
}
break;
}
}
}
CloseHandle(ProcHandle);
}
return NULL;
}
int main(void)
{
void* base = imageBase((char*)"ac_client.exe", (char*)"ac_client.exe");
std::cout << "0x" << std::hex << base;
}

Can't obtain accurate information of available memory in the heap

all
I use the following function to obtain information about available memory and largest contiguous block in the heap.
int GetLargestContiguousMemory()
{
MEMORY_BASIC_INFORMATION mbi;
DWORD start = 0;
bool recording = false;
DWORD freestart = 0, largestFreestart = 0;
__int64 free = 0, largestFree = 0; while (true)
{
// SIZE_T s = VirtualQueryEx(hproc, reinterpret_cast<lpvoid>(start), &mbi, sizeof(mbi));
SIZE_T s = VirtualQueryEx(GetCurrentProcess(), (void*)(start), &mbi, sizeof(mbi));
if (s != sizeof(mbi))
{
if (GetLastError() != ERROR_INVALID_PARAMETER)
//return ReportError(GetLastError(), _T("Failed to VirtualQueryEx at %08x"), start);
printf("Failed to VirtualQueryEx at %08x", start);
else
break;
}
if (mbi.State == MEM_FREE)
{
if (!recording)
freestart = start;
free += mbi.RegionSize;
recording = true;
}
else
{
if (recording)
{
if (free > largestFree)
{
largestFree = free;
largestFreestart = freestart;
}
}
free = 0;
recording = false;
}
start += mbi.RegionSize;
}
return largestFree;
}
int GetHeapAvailableMemory()
{
MEMORY_BASIC_INFORMATION mbi;
DWORD start = 0;
bool recording = false;
DWORD freestart = 0, largestFreestart = 0;
__int64 free = 0, largestFree = 0;
while (true)
{
// SIZE_T s = VirtualQueryEx(hproc, reinterpret_cast<lpvoid>(start), &mbi, sizeof(mbi));
SIZE_T s = VirtualQueryEx(GetCurrentProcess(), (void*)(start), &mbi, sizeof(mbi));
if (s != sizeof(mbi))
{
if (GetLastError() != ERROR_INVALID_PARAMETER)
//return ReportError(GetLastError(), _T("Failed to VirtualQueryEx at %08x"), start);
printf("Failed to VirtualQueryEx at %08x", start);
else
break;
}
if (mbi.State == MEM_FREE)
{
if (!recording)
freestart = start;
free += mbi.RegionSize;
}
start += mbi.RegionSize;
}
return free;
}
In my program, I use operator new to allocate memory in a loop, but the above function return same value for several iterations, and the returned value changes suddenly. It shows the size of the available memory in the heap is reduced by 8M bytes.
I can't understand that. Is the function correct to return the size of available memory in the heap?
Thanks.
Jogging

Change Mac address by adapter description

I'm using the excellent tool provided by Nate True # http://devices.natetrue.com/macshift/
It changes the Mac address by the adapter name. This is the source code:
const int versionMajor = 1;
const int versionMinor = 1;
#include <windows.h>
#include <objbase.h>
#include <netcon.h>
#include <stdio.h>
#include "validmacs.h"
void SetMAC(char * AdapterName, char * NewMAC) {
HKEY hListKey = NULL;
HKEY hKey = NULL;
RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
0, KEY_READ, &hListKey);
if (!hListKey) {
printf("Failed to open adapter list key\n");
return;
}
FILETIME writtenTime;
char keyNameBuf[512], keyNameBuf2[512];
DWORD keyNameBufSiz = 512;
DWORD crap;
int i = 0;
bool found = false;
while (RegEnumKeyEx(hListKey, i++, keyNameBuf, &keyNameBufSiz, 0, NULL, NULL, &writtenTime)
== ERROR_SUCCESS) {
_snprintf(keyNameBuf2, 512, "%s\\Connection", keyNameBuf);
hKey = NULL;
RegOpenKeyEx(hListKey, keyNameBuf2, 0, KEY_READ, &hKey);
if (hKey) {
keyNameBufSiz = 512;
if (RegQueryValueEx(hKey, "Name", 0, &crap, (LPBYTE)keyNameBuf2, &keyNameBufSiz)
== ERROR_SUCCESS && strcmp(keyNameBuf2, AdapterName) == 0) {
printf("Adapter ID is %s\n", keyNameBuf);
found = true;
break;
}
RegCloseKey(hKey);
}
keyNameBufSiz = 512;
}
RegCloseKey(hListKey);
if (!found) {
printf("Could not find adapter name '%s'.\nPlease make sure this is the name you gave it in Network Connections.\n", AdapterName);
return;
}
RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}",
0, KEY_READ, &hListKey);
if (!hListKey) {
printf("Failed to open adapter list key in Phase 2\n");
return;
}
i = 0;
char buf[512];
while (RegEnumKeyEx(hListKey, i++, keyNameBuf2, &keyNameBufSiz, 0, NULL, NULL, &writtenTime)
== ERROR_SUCCESS) {
hKey = NULL;
RegOpenKeyEx(hListKey, keyNameBuf2, 0, KEY_READ | KEY_SET_VALUE, &hKey);
if (hKey) {
keyNameBufSiz = 512;
if ((RegQueryValueEx(hKey, "NetCfgInstanceId", 0, &crap, (LPBYTE)buf, &keyNameBufSiz)
== ERROR_SUCCESS) && (strcmp(buf, keyNameBuf) == 0)) {
RegSetValueEx(hKey, "NetworkAddress", 0, REG_SZ, (LPBYTE)NewMAC, strlen(NewMAC) + 1);
//printf("Updating adapter index %s (%s=%s)\n", keyNameBuf2, buf, keyNameBuf);
//break;
}
RegCloseKey(hKey);
}
keyNameBufSiz = 512;
}
RegCloseKey(hListKey);
}
void ResetAdapter(char * AdapterName) {
struct _GUID guid = {0xBA126AD1,0x2166,0x11D1,0};
memcpy(guid.Data4, "\xB1\xD0\x00\x80\x5F\xC1\x27\x0E", 8);
unsigned short * buf = new unsigned short[strlen(AdapterName)+1];
void (__stdcall *NcFreeNetConProperties) (NETCON_PROPERTIES *);
HMODULE NetShell_Dll = LoadLibrary("Netshell.dll");
if (!NetShell_Dll) {
printf("Couldn't load Netshell.dll\n");
return;
}
NcFreeNetConProperties = (void (__stdcall *)(struct tagNETCON_PROPERTIES *))GetProcAddress(NetShell_Dll, "NcFreeNetconProperties");
if (!NcFreeNetConProperties) {
printf("Couldn't load required DLL function\n");
return;
}
for (unsigned int i = 0; i <= strlen(AdapterName); i++) {
buf[i] = AdapterName[i];
}
CoInitialize(0);
INetConnectionManager * pNCM = NULL;
HRESULT hr = ::CoCreateInstance(guid,
NULL,
CLSCTX_ALL,
__uuidof(INetConnectionManager),
(void**)&pNCM);
if (!pNCM)
printf("Failed to instantiate required object\n");
else {
IEnumNetConnection * pENC;
pNCM->EnumConnections(NCME_DEFAULT, &pENC);
if (!pENC) {
printf("Could not enumerate Network Connections\n");
}
else {
INetConnection * pNC;
ULONG fetched;
NETCON_PROPERTIES * pNCP;
do {
pENC->Next(1, &pNC, &fetched);
if (fetched && pNC) {
pNC->GetProperties(&pNCP);
if (pNCP) {
if (wcscmp(pNCP->pszwName, buf) == 0) {
pNC->Disconnect();
pNC->Connect();
}
NcFreeNetConProperties(pNCP);
}
}
} while (fetched);
pENC->Release();
}
pNCM->Release();
}
FreeLibrary(NetShell_Dll);
CoUninitialize ();
}
bool IsValidMAC(char * str) {
if (strlen(str) != 12) return false;
for (int i = 0; i < 12; i++) {
if ((str[i] < '0' || str[i] > '9')
&& (str[i] < 'a' || str[i] > 'f')
&& (str[i] < 'A' || str[i] > 'F')) {
return false;
}
}
return true;
}
void ShowHelp() {
printf("Usage: macshift [options] [mac-address]\n\n");
printf("Options:\n");
printf("\t-i [adapter-name] The adapter name from Network Connections.\n");
printf("\t-r Uses a random MAC address. This is the default.\n");
printf("\t-d Restores the original MAC address.\n");
printf("\t--help Shows this screen.\n\n");
printf("Macshift uses special undocumented functions in the Windows COM Interface that\n");
printf(" allow you to change an adapter's MAC address without needing to restart.\n");
printf("When you change a MAC address, all your connections are closed automatically\n");
printf(" and your adapter is reset.\n");
}
//Generates a random MAC that is actually plausible
void RandomizeMAC(char * newmac) {
_snprintf(newmac, 6, "%06X", rand() % numMacs);
for (int i = 3; i < 6; i++) {
_snprintf(&newmac[i*2], 2, "%02X", rand() & 0xFF);
}
newmac[12] = 0;
}
int main(int argc, char * * argv) {
printf("Macshift v%i.%i, MAC Changing Utility by Nathan True, macshift#natetrue.com\n\n", versionMajor, versionMinor);
//Parse commandline arguments
char * adapter = "Wireless";
char newmac[13];
int i;
if (argc == 1) {
ShowHelp();
return 0;
}
//Start out with a random MAC
srand(GetTickCount());
RandomizeMAC(newmac);
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case '-': //Extended argument
if (strcmp(argv[i]+2, "help") == 0) {
ShowHelp();
return 0;
}
break;
case 'r': //Random setting, this is the default
break;
case 'i': //Adapter name follows
if (argc > i + 1) adapter = argv[++i];
break;
case 'd': //Reset the MAC address
newmac[0] = 0;
}
}
else {
if (IsValidMAC(argv[i])) strncpy(newmac, argv[i], 13);
else printf("MAC String %s is not valid. MAC addresses must m/^[0-9a-fA-F]{12}$/.\n", argv[i]);
}
}
printf("Setting MAC on adapter '%s' to %s...\n", adapter, newmac[0] ? newmac : "original MAC");
SetMAC(adapter, newmac);
printf("Resetting adapter...\n");
fflush(stdout);
ResetAdapter(adapter);
printf("Done\n");
return 0;
}
I would like to change the Mac address by the description of an adapter, in addition to the name. So I need to modify this code so that if a matching name is not found, it falls back to changing the mac based on the description.
This is an example adapter:
name: Local Area Connection
description: Marvell Yukon 88E8055 PCI-E Gigabit Ethernet Controller
Unfortunately, being a Java developer I have limited experience with C++, so any help would be greatly appreciated.
Here's a C sample of GetAdaptersInfo, it prints out each adapters name and description (you can easily adapt it for your code by calling SetMAC on a match):
VOID EnumerateNetworkAdapters(VOID)
{
ULONG len = 0;
if (ERROR_BUFFER_OVERFLOW == GetAdaptersInfo(NULL, &len))
{
IP_ADAPTER_INFO *ipai;
ipai = malloc(len);
if (NO_ERROR == GetAdaptersInfo(ipai, &len))
{
IP_ADAPTER_INFO *p = ipai;
do
{
printf("name=%s description=%s\n", p->AdapterName, p->Description);
}
while (p = p->Next);
}
free(ipai);
}
}
Link against "Iphlpapi.lib".
Use GetAdaptersAddresses to get the adapter name(PIP_ADAPTER_ADDRESSES::FriendlyName) by comparing the description(PIP_ADAPTER_ADDRESSES::Description) before the call to SetMAC(). Example can be found in above MSDN link.