AHK version:
Code:
GetAddress(Window) {
WinGet, hWnd, ID, %Window%
return DllCall(A_PtrSize = 4
? "GetWindowLong"
: "GetWindowLongPtr"
, "Ptr", hWnd, "Int", -6, "Int64")
}
GetHandle(Window) {
WinGet, pid, PID, %Window%
return DllCall("OpenProcess", "Int", 56, "Char", 0, "UInt", pid, "UInt")
}
ReadInt64(Handle, Address) {
VarSetCapacity(Buffer, 8, 0)
DllCall("ReadProcessMemory", "UInt", Handle, "Ptr", Address, "Ptr", &Buffer, "Int64", 8)
Loop 8
Result += *(&Buffer + A_Index-1) << 8*(A_Index-1)
return Result
}
WriteUInt(Handle, Address, Value)
{
VarSetCapacity(Buffer, 4, 0)
NumPut(Value, Buffer, 0, "UInt")
return DllCall("WriteProcessMemory", "Uint", Handle, "Ptr", Address, "Ptr", &Buffer, "UInt", 4)
}
Handle := GetHandle("Fallout76")
if (Handle > 0) {
Address := GetAddress("Fallout76")
if (Address > 0) {
ListPointer := ReadInt64(Handle, Address + 89666888)
if (ListPointer > 48) {
A_ListPointer := ReadInt64(Handle, ListPointer + 1048)
if (A_ListPointer > 48) {
B_ListPointer := ReadInt64(Handle, ListPointer + 1384)
if (B_ListPointer > 48) {
A_ListBuffer := ReadInt64(Handle, A_ListPointer + 5064)
if (A_ListBuffer > 48) {
B_ListBuffer := ReadInt64(Handle, B_ListPointer + 6368)
if (B_ListBuffer > 48) {
A_ListCheck := ReadInt64(Handle, A_ListBuffer)
if (A_ListCheck == Address + 55898504) {
B_ListCheck := ReadInt64(Handle, B_ListBuffer)
if (B_ListCheck == Address + 55860432) {
WriteUInt(Handle, A_ListBuffer + 32, 1409003)
WriteUInt(Handle, B_ListBuffer + 568, 256)
}
else {
MsgBox B_ListCheck failed
}
}
else {
MsgBox A_ListCheck failed
}
}
else {
MsgBox Failed to get B_ListBuffer
}
}
else {
MsgBox Failed to get A_ListBuffer
}
}
else {
MsgBox Failed to get B_ListPointer
}
}
else {
MsgBox Failed to get A_ListPointer
}
}
else {
MsgBox Failed to get ListPointer
}
}
else {
MsgBox Failed to get Address
}
}
else {
MsgBox Failed to get Handle
}
C++ version:
Code:
//fallout 76 dupe 2019
//place items in power armor station
//scrap the C.A.M.P workshop object
//tell a friend to take items from power armor station
//drop a item to rollback power armor station inventory
#include <iostream>
#include <Windows.h>
#include <Psapi.h>
using namespace std;
#define list 0x5583548//75 71 48 8B 05 ? ? ? ? 80 B8 03 1A 00 00 00 75 61
bool dupe(HWND hWnd);
//https://stackoverflow.com/a/51731567
static BOOL CALLBACK enumWindowCallback(HWND hWnd, LPARAM lparam) {
int length = GetWindowTextLength(hWnd);
char* buffer = new char[length + 1];
GetWindowText(hWnd, buffer, length + 1);
if (!strcmp(buffer, "Fallout76")) {
dupe(hWnd);
}
return TRUE;
}
//https://stackoverflow.com/a/26573045
DWORD_PTR GetProcessBaseAddress(DWORD processID)
{
DWORD_PTR baseAddress = 0;
HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
HMODULE *moduleArray;
LPBYTE moduleArrayBytes;
DWORD bytesRequired;
if (processHandle)
{
if (EnumProcessModules(processHandle, NULL, 0, &bytesRequired))
{
if (bytesRequired)
{
moduleArrayBytes = (LPBYTE)LocalAlloc(LPTR, bytesRequired);
if (moduleArrayBytes)
{
unsigned int moduleCount;
moduleCount = bytesRequired / sizeof(HMODULE);
moduleArray = (HMODULE *)moduleArrayBytes;
if (EnumProcessModules(processHandle, moduleArray, bytesRequired, &bytesRequired))
{
baseAddress = (DWORD_PTR)moduleArray[0];
}
LocalFree(moduleArrayBytes);
}
}
}
CloseHandle(processHandle);
}
return baseAddress;
}
bool dupe(HWND hWnd) {
DWORD pid;
GetWindowThreadProcessId(hWnd, &pid);
if (!pid) return false;
DWORD_PTR base = GetProcessBaseAddress(pid);
if (!base) return false;
HANDLE h = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, 0, pid);
if (!h) return false;
__int64 lists = base + list;
if (!ReadProcessMemory(h, (PVOID*)lists, &lists, 8, 0)) return false;
__int64 a_buffer = lists + 0x418;
if (!ReadProcessMemory(h, (PVOID*)a_buffer, &a_buffer, 8, 0)) return false;
__int64 a_list[2000];
if (!ReadProcessMemory(h, (PVOID*)a_buffer, &a_list, 8 * 2000, 0)) return false;
a_buffer = 0;
for (size_t i = 0; i < 2000; i += 1) {
__int32 a_editor;
a_list[i] += 0x20;
if (!ReadProcessMemory(h, (PVOID*)a_list[i], &a_editor, 4, 0)) continue;
if (a_editor != 0x12D065) continue;
a_list[i] -= 0x20;
a_buffer = a_list[i];
break;
}
if (!a_buffer) return false;
a_buffer += 0x20;
__int64 b_buffer = lists + 0x568;
if (!ReadProcessMemory(h, (PVOID*)b_buffer, &b_buffer, 8, 0)) return false;
__int64 b_list[2000];
if (!ReadProcessMemory(h, (PVOID*)b_buffer, &b_list, 8 * 2000, 0)) return false;
b_buffer = 0;
for (size_t i = 0; i < 2000; i += 1) {
__int32 b_editor;
b_list[i] += 0x20;
if (!ReadProcessMemory(h, (PVOID*)b_list[i], &b_editor, 4, 0)) continue;
if (b_editor != 0x157FEB) continue;
b_list[i] -= 0x20;
b_buffer = b_list[i];
break;
}
if (!b_buffer) return false;
b_buffer += 0x238;
__int32 a_editor = 0x157FEB;
if (!WriteProcessMemory(h, (PVOID*)a_buffer, &a_editor, 4, 0)) return false;
__int8 b_editor = 0;
if (!WriteProcessMemory(h, (PVOID*)b_buffer, &b_editor, 1, 0)) return false;
return true;
}
int main() {
EnumWindows(enumWindowCallback, NULL);
return 0;
}
Steps:
Download and install AutoHotKey 1.1.31.00
Copy/paste the script to notepad and save it as "Dupe.ahk"
Open Fallout 76 and run the script
Place items in a power armor station at your camp
Scrap the C.A.M.P workshop object
Tell a friend to run the script and take the items from your power armor station
Drop a item to roll back power armor station inventory
The items will now be in your friends inventory, and in the power armor station