Register for your free account! | Forgot your password?

Go Back   elitepvpers > Popular Games > Silkroad Online
You last visited: Today at 23:10

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



changing chat text color ?

Discussion on changing chat text color ? within the Silkroad Online forum part of the Popular Games category.

Reply
 
Old   #1
 
elite*gold: 0
Join Date: Feb 2008
Posts: 2
Received Thanks: 0
changing chat text color ?

is it possible to change chat text color ?
i tried to search but i didn't find anything.
lalalagirl is offline  
Old 08/08/2009, 20:44   #2

 
elite*gold: 260
Join Date: Aug 2008
Posts: 560
Received Thanks: 3,779
Quote:
Originally Posted by lalalagirl View Post
is it possible to change chat text color ?
i tried to search but i didn't find anything.
I wrote code to do it a long time ago. The first way I did it was to perform client edits via WriteProcessMemory through a secondary program. That would work for all chat types except for All Chat right now due to how the client code is setup.

The second method I used was to create a codecave in the client to process the chat color logic. You can get the current chat type and then specify a custom color for it. That is much easier to work with, but requires the use of a loader and injected DLL. You could use my guides to do it though but I'm not going to myself.

Here's the code in the latest 205 client that has to deal with chat colors.

Code:
007A37C7   .  8078 04 00    CMP BYTE PTR DS:[EAX+4],0
007A37CB   .^ 0F84 B2FEFFFF JE sro_clie.007A3683
007A37D1   >  BD FEFF9FFF   MOV EBP,FF9FFFFE                         ;  Case A of switch 007A37B3
007A37D6   .  EB 34         JMP SHORT sro_clie.007A380C
007A37D8   >  BD 00FFFFFF   MOV EBP,-100                             ;  Case 6 of switch 007A37B3
007A37DD   .  EB 2D         JMP SHORT sro_clie.007A380C
007A37DF   >  BD C3AEFFFF   MOV EBP,FFFFAEC3                         ;  Cases 3,7 of switch 007A37B3
007A37E4   .  EB 26         JMP SHORT sro_clie.007A380C
007A37E6   >  BD 41B5FFFF   MOV EBP,FFFFB541                         ;  Case 5 of switch 007A37B3
007A37EB   .  EB 1F         JMP SHORT sro_clie.007A380C
007A37ED   >  BD 73F5C2FF   MOV EBP,FFC2F573                         ;  Case B of switch 007A37B3
007A37F2   .  EB 18         JMP SHORT sro_clie.007A380C
007A37F4   >  BD D0FF9AFF   MOV EBP,FF9AFFD0                         ;  Case 4 of switch 007A37B3
007A37F9   .  EB 11         JMP SHORT sro_clie.007A380C
007A37FB   >  BD F8ADDBFF   MOV EBP,FFDBADF8                         ;  Case D of switch 007A37B3
007A3800   .  EB 0A         JMP SHORT sro_clie.007A380C
007A3802   >  BD FFC764FF   MOV EBP,FF64C7FF                         ;  Case 10 of switch 007A37B3
007A3807   .  EB 03         JMP SHORT sro_clie.007A380C
007A3809   >  83CD FF       OR EBP,FFFFFFFF                          ;  Default case of switch 007A37B3
007A380C   >  B8 07000000   MOV EAX,7
You should be able to follow the colors in a graphics program that allows you to use hex/decimal for RGB. The colors are stored backwards in memory so FEFF9FFF is color (ARGB) FF 9F FF FE, or the color for whisper chat.

Here's the updated code to the project I wrote back in Feb. 07. The concept is pretty simple. Just write out the new hex values for the colors in the Silkroad process. You need to be running the program in Administrator in Vista/Win7 as well.

SilkroadChatColor.cpp
Code:
#include "cProcess.h"

#include <windows.h>
#include <math.h>
#include <stdio.h>
#include <fstream>
#include <sstream>

// Main program window
HWND hwnd = 0;

// Array of addresses to make for easier access
unsigned long addrs[6];
unsigned long defs[6];
unsigned long curs[6];
HWND hwnds[6];
HWND preview[6];

// Whisper
HWND lblWhisper = 0;
HWND editWhisper = 0;
HWND btnDefWhisper = 0;
unsigned long addrWhisper = 0x7A37D1;
unsigned long defColorWhisper = 0xFF9FFFFE;

// Global
HWND lblGlobal = 0;
HWND editGlobal = 0;
HWND btnDefGlobal = 0;
unsigned long addrGlobal = 0x7A37D8;
unsigned long defColorGlobal = 0xFFFFFF00;

// Notice
HWND lblNotice = 0;
HWND editNotice = 0;
HWND btnDefNotice = 0;
unsigned long addrNotice = 0x7A37DF;
unsigned long defColorNotice = 0xFFFFAEC3;

// Guild
HWND lblGuild = 0;
HWND editGuild = 0;
HWND btnDefGuild = 0;
unsigned long addrGuild = 0x7A37E6;
unsigned long defColorGuild = 0xFFFFB541;

// Union
HWND lblUnion = 0;
HWND editUnion = 0;
HWND btnDefUnion = 0;
unsigned long addrUnion = 0x7A37ED;
unsigned long defColorUnion = 0xFFC2F573;

// Party
HWND lblParty = 0;
HWND editParty = 0;
HWND btnDefParty = 0;
unsigned long addrParty = 0x7A37F4;
unsigned long defColorParty = 0xFF9AFFD0;

// Set chat color button
HWND btnColorize = 0;
HWND btnPerm = 0;

// Get the current color a chat type
HWND btnGetWhisper = 0;
HWND btnGetGlobal = 0;
HWND btnGetNotice = 0;
HWND btnGetGuild = 0;
HWND btnGetUnion = 0;
HWND btnGetParty = 0;
HWND btnGetAll = 0;

// Defines for the button messages
#define BTN_DEF_COLOR_WHISPER	1
#define BTN_DEF_COLOR_GLOBAL	2
#define BTN_DEF_COLOR_NOTICE	3
#define BTN_DEF_COLOR_GUILD		4
#define BTN_DEF_COLOR_UNION		5
#define BTN_DEF_COLOR_PARTY		6
#define BTN_DEF_COLOR_ALL		7
#define BTN_COLORIZE_ON			8
#define BTN_COLORIZE_GET		9


#define BTN_PREVIEW_COLOR_WHSIPER	11
#define BTN_PREVIEW_COLOR_GLOBAL	12
#define BTN_PREVIEW_COLOR_NOTICE	13
#define BTN_PREVIEW_COLOR_GUILD		14
#define BTN_PREVIEW_COLOR_UNION		15
#define BTN_PREVIEW_COLOR_PARTY		16
#define BTN_PREVIEW_COLOR_ALL		17

#define BTN_GET_COLOR_WHISPER	18
#define BTN_GET_COLOR_GLOBAL	19
#define BTN_GET_COLOR_NOTICE	20
#define BTN_GET_COLOR_GUILD		21
#define BTN_GET_COLOR_UNION		22
#define BTN_GET_COLOR_PARTY		23
#define BTN_GET_COLOR_ALL		24

// cProcess class object used to make working with processes a lot easier ;)
cProcess sro;

unsigned long CaptionToHex(HWND h)
{
	// Store the actual hex string
	unsigned char data[5] = {0};
	// Store the ascii-hex string
	char temp[32] = {0};
	// The alpha should be FF, opaque (don't think font supports alpha)
	temp[0] = 'F';
	temp[1] = 'F';
	// Get the desired window's color
	GetWindowText(h, temp + 2, 7);
	// Store the final value
	int value = 0;
	// We have to reverse the digits for hex form
	int index = 3;
	// Loop though all tuples of characters
	for(int y = 0; y < 8; y += 2)
	{
		int tuple1 = 15, tuple2 = 15;
		// Store current character
		unsigned char cur = temp[y];
		// If it's A - F, convert it to 10 - 15
		if(cur >= 'A' && cur <= 'F')
			tuple1 = cur - 'A' + 10;
		// If it's 0 - 9, convert it to 0 - 9
		else if(cur >= '0' && cur <= '9')
			tuple1 = cur - '0';

		// Store current character
		cur = temp[y + 1];
		// If it's A - F, convert it to 10 - 15
		if(cur >= 'A' && cur <= 'F')
			tuple2 = cur - 'A' + 10;
		// If it's 0 - 9, convert it to 0 - 9
		else if(cur >= '0' && cur <= '9')
			tuple2 = cur - '0';
		// Convert the two numbers into a unsigned character
		value = tuple2 + 16 * tuple1;
		// Store the final color value for this color component
		data[index--] = value;
	}
	// Store a pointer of the final color value as a unsigned long
	unsigned long* ptr = (unsigned long*)data;
	return *ptr;
}

void DrawColorPreview(HDC hdc, int x, int y, unsigned long color) 
{
	color = color & 0x00FFFFFF;
	HBRUSH NewBrush = CreateSolidBrush(RGB(GetBValue(color),GetGValue(color),GetRValue(color)));
	SelectObject(hdc, NewBrush);
	Rectangle(hdc, x, y, x + 18, y + 18);
	DeleteObject(NewBrush);
}

// Get the current chat colors
void GetCurrentChatColors(int x)
{
	// Array to hold the data
	unsigned char buffer[5] = {0};
	// Read in the memory location
	if(!sro.ReadArray(addrs[x], buffer, 5))
	{
		MessageBox(hwnd, "Memory address could not be read.", "Fatal Error", MB_OK | MB_ICONERROR);
		return;
	}
	char temp[256] = {0};
	// Store the color components into the array
	_snprintf(temp, 255, "%.2X%.2X%.2X", buffer[3], buffer[2], buffer[1]);
	// Write the entire RGB color string to the edit box
	SetWindowText(hwnds[x], temp);
}

void GeneratePreview(HWND btn, int button)
{
	curs[button] = CaptionToHex(btn);
	RECT r;
	r.left = 284;
	r.right = r.left + 18;
	r.top = 10 + button * 30;
	r.bottom = r.top + 18;
	InvalidateRect(hwnd, &r, true);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT Ps;
	HDC hdc;
	switch(msg)
	{
	case WM_PAINT:
		{
			hdc = BeginPaint(hwnd, &Ps);
			for(int x = 0; x < 6; ++x)
				DrawColorPreview(hdc, 284, 10 + x * 30, curs[x]);
			EndPaint(hwnd, &Ps);
		}
		break;

	case WM_COMMAND:
		{
			if(LOWORD(wParam) == BTN_COLORIZE_ON)
			{
				// Loop though all chat colors
				for(int x = 0; x < 6; ++x)
				{
					int ptr = CaptionToHex(hwnds[x]);
					// Write the color value to memory
					sro.Write(addrs[x] + 1, ptr);
				}
			}
			else if(LOWORD(wParam) >= BTN_GET_COLOR_WHISPER && LOWORD(wParam) <= BTN_GET_COLOR_ALL)
			{
				int button = LOWORD(wParam) - BTN_GET_COLOR_WHISPER;
				GetCurrentChatColors(button);
				GeneratePreview(hwnds[button], button);
			}
			else if(LOWORD(wParam) >= BTN_DEF_COLOR_WHISPER && LOWORD(wParam) <= BTN_DEF_COLOR_ALL)
			{
				// Save the real button #
				int button = LOWORD(wParam) - 1;
				// Buffer to hold the default value
				char temp[256] = {0};
				// Save the default value to the buffer
				sprintf(temp, "%X", defs[button]);
				// Write the default value to the window
				SetWindowText(hwnds[button], temp + 2);
				GeneratePreview(hwnds[button], button);
			}
			else if(LOWORD(wParam) >= BTN_PREVIEW_COLOR_WHSIPER && LOWORD(wParam) <= LOWORD(wParam))
			{
				int button = LOWORD(wParam) - BTN_PREVIEW_COLOR_WHSIPER;
				GeneratePreview(hwnds[button], button);
			}
		}
		break; 

	case WM_CLOSE:
		{
			DestroyWindow(hwnd);
		}
		break;

	case WM_DESTROY:
		{
			PostQuitMessage(0);
		}
		break;

	default:
		{
			return DefWindowProc(hwnd, msg, wParam, lParam);
		}
	}
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEX wc = {0};
	MSG msg = {0};

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WndProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = GetModuleHandle(0);
	wc.hIcon         = LoadIcon(NULL, MAKEINTRESOURCE(101));
	wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+6);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = "SROChatColor";
	wc.hIconSm       = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(101), IMAGE_ICON, 16, 16, 0);;

	// Win32 stuff to create the program
	if(!RegisterClassEx(&wc))
	{
		MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONERROR | MB_OK);
		return 0;
	}

	// Create main window
	hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "SROChatColor", "Silkroad Chat Color - By: Drew Benton", WS_OVERLAPPEDWINDOW ^ WS_MAXIMIZEBOX ^ WS_THICKFRAME, CW_USEDEFAULT, CW_USEDEFAULT, 480, 290, NULL, NULL, hInstance, NULL);
	if(hwnd == NULL)
	{
		MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONERROR | MB_OK);
		return 0;
	}

	// Try to open the sro client
	if(!sro.Open("sro_client.exe"))
	{
		MessageBox(0, "Cannot find your sro_client.exe", "Error!", MB_ICONERROR | MB_OK);
		return -1;
	}

	// Store the addresses
	addrs[0] = addrWhisper;
	addrs[1] = addrGlobal;
	addrs[2] = addrNotice;
	addrs[3] = addrGuild;
	addrs[4] = addrUnion;
	addrs[5] = addrParty;
	//addrs[6] = addrAll;

	// Store default colors
	defs[0] = defColorWhisper;
	defs[1] = defColorGlobal;
	defs[2] = defColorNotice;
	defs[3] = defColorGuild;
	defs[4] = defColorUnion;
	defs[5] = defColorParty;
	//defs[6] = defColorAll;

	// Store defaults
	for(int x = 0; x < 6; ++x)
		curs[x] = defs[x];

	// Coords of controls
	int X = 0; int Y = 0; int W = 0; int H = 0;

	// Whisper
	X = 10; Y = 10; W = 125; H = 20;
	lblWhisper = CreateWindowEx(0, "STATIC", "Whisper Chat: ", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 110;
	editWhisper = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 312; W = 70;
	btnDefWhisper = CreateWindowEx(0, "BUTTON", "Default", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_DEF_COLOR_WHISPER, NULL, 0);
	X = 392;
	btnGetWhisper = CreateWindowEx(0, "BUTTON", "Current", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_GET_COLOR_WHISPER, NULL, 0);
	X = 250; W = 24;
	preview[0] = CreateWindowEx(0, "BUTTON", "?", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_PREVIEW_COLOR_WHSIPER, NULL, 0);

	// Global
	X = 10; Y = 40; W = 125; H = 20;
	lblGlobal = CreateWindowEx(0, "STATIC", "Global Chat: ", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 110;
	editGlobal = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 312; W = 70;
	btnDefWhisper = CreateWindowEx(0, "BUTTON", "Default", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_DEF_COLOR_GLOBAL, NULL, 0);
	X = 392;
	btnGetGlobal = CreateWindowEx(0, "BUTTON", "Current", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_GET_COLOR_GLOBAL, NULL, 0);
	X = 250; W = 24;
	preview[1] = CreateWindowEx(0, "BUTTON", "?", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_PREVIEW_COLOR_GLOBAL, NULL, 0);

	// Notice
	X = 10; Y = 70; W = 125; H = 20;
	lblNotice = CreateWindowEx(0, "STATIC", "Notice Chat: ", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 110;
	editNotice = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 312; W = 70;
	btnDefNotice = CreateWindowEx(0, "BUTTON", "Default", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_DEF_COLOR_NOTICE, NULL, 0);
	X = 392;
	btnGetNotice = CreateWindowEx(0, "BUTTON", "Current", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_GET_COLOR_NOTICE, NULL, 0);
	X = 250; W = 24;
	preview[2] = CreateWindowEx(0, "BUTTON", "?", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_PREVIEW_COLOR_NOTICE, NULL, 0);

	// Guild
	X = 10; Y = 100; W = 125; H = 20;
	lblGuild = CreateWindowEx(0, "STATIC", "Guild Chat: ", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 110;
	editGuild = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 312; W = 70;
	btnDefGuild = CreateWindowEx(0, "BUTTON", "Default", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_DEF_COLOR_GUILD, NULL, 0);
	X = 392;
	btnGetGuild = CreateWindowEx(0, "BUTTON", "Current", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_GET_COLOR_GUILD, NULL, 0);
	X = 250; W = 24;
	preview[3] = CreateWindowEx(0, "BUTTON", "?", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_PREVIEW_COLOR_GUILD, NULL, 0);

	// Union
	X = 10; Y = 130; W = 125; H = 20;
	lblUnion = CreateWindowEx(0, "STATIC", "Union Chat: ", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 110;
	editUnion = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 312; W = 70;
	btnDefUnion = CreateWindowEx(0, "BUTTON", "Default", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_DEF_COLOR_UNION, NULL, 0);
	X = 392;
	btnGetUnion = CreateWindowEx(0, "BUTTON", "Current", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_GET_COLOR_UNION, NULL, 0);
	X = 250; W = 24;
	preview[4] = CreateWindowEx(0, "BUTTON", "?", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_PREVIEW_COLOR_UNION, NULL, 0);

	// Party
	X = 10; Y = 160; W = 125; H = 20;
	lblParty = CreateWindowEx(0, "STATIC", "Party Chat: ", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 110;
	editParty = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 312; W = 70;
	btnDefParty = CreateWindowEx(0, "BUTTON", "Default", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_DEF_COLOR_PARTY, NULL, 0);
	X = 392;
	btnGetParty = CreateWindowEx(0, "BUTTON", "Current", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_GET_COLOR_PARTY, NULL, 0);
	X = 250; W = 24;
	preview[5] = CreateWindowEx(0, "BUTTON", "?", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_PREVIEW_COLOR_PARTY, NULL, 0);

	// Set chat color button
	X = 312; Y = 220; W = 150; H = 30;
	btnColorize = CreateWindowEx(0, "BUTTON", "Change Chat Colors!", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_COLORIZE_ON, NULL, 0);

	// Store the edit handles to make life easier
	hwnds[0] = editWhisper;
	hwnds[1] = editGlobal;
	hwnds[2] = editNotice;
	hwnds[3] = editGuild;
	hwnds[4] = editUnion;
	hwnds[5] = editParty;
	//hwnds[6] = editAll;

	// Start the program out by getting the current colors stored in memory
	for(int x = 0; x < 6; ++x)
		GetCurrentChatColors(x);

		// Reactivate this program
	SetForegroundWindow(hwnd);

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

	while(msg.message != WM_QUIT)
	{
		if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			WaitMessage();
		}
	}
	return 0;
}
cProcess.h
Code:
/*****************************************************************************/
/* cProcess
/* By; Drew Benton
/*
/* This class was written to make working with processes a lot easier. With 
/* this class, the user will be able to open a process and read from memory
/* or write to memory. It is designed with simplicty and ease of use in mind.
/* If you have any questions or comments e-mail me at 
/*
/******************************************************************************/

#ifndef CPROCESS_H_
#define CPROCESS_H_

#include <windows.h>
#include <tlhelp32.h>
#include <string>

// Display the current error to the user via a message box
void ShowError(LPTSTR lpszFunction);

// The callback function used for processing HWNDs
BOOL CALLBACK enumCallbackFunc(HWND hwnd, LPARAM lparam);

class cProcess
{
public:
	// The process entry for the process
	PROCESSENTRY32 pe32;

	// Handle to the process
	HANDLE handle;

	// One of the HWNDs associated with the process
	HWND hwnd;

public:
	/******************************************************************************************/
	//								MEMBER FUNCTIONS REFERENCE								  //
	/******************************************************************************************/
	/*	// This is the constructor for the cProcess class.
	/*	cProcess();
	/*	// This is the destructor for the cProcess class.
	/*	~cProcess();
	/*
	/*	// This function will open the desired executable's process.
	/*	bool Open(
	/*		const std::string& exeName, 
	/*		bool lookForWindow = true,
	/*		DWORD dwDesiredAccess = PROCESS_ALL_ACCESS, 
	/*		BOOL bInhereitHandle = FALSE);
	/*
	/*	// This function will close the opened process.
	/*	void Close();
	/*
	/*	// This function will read exactly 'one' unit of the passed datatype specified.
	/*	template <class type> 
	/*	bool Read(
	/*		unsigned long address, 
	/*		type& buffer);
	/*
	/*	// This function will read exactly sizeOfBuffer units of the 
	/*	// passed datatype specified or until 'stopValue' is read.
	/*	template <class type>
	/*	bool ReadArray(
	/*		unsigned long address, 
	/*		type* buffer, 
	/*		int sizeOfBuffer, 
	/*		type stopValue);
	/*
	/*	// This function will read exactly sizeOfBuffer units of the passed datatype specified.
	/*	template <class type>
	/*	bool ReadArray(
	/*		unsigned long address, 
	/*		type* buffer, 
	/*		int sizeOfBuffer);
	/*
	/*	// This function will write the passed variable to memory.
	/*	template <class type>
	/*	bool Write(
	/*		unsigned long address, 
	/*		type& buffer);
	/*
	/*	// This function will write the buffer of passed datatype 
	/*	// specified into the memory address specificed.
	/*	template <class type>
	/*	bool WriteArray(
	/*		unsigned long address, 
	/*		type* buffer, 
	/*		int sizeOfBuffer);
	/*****************************************************************************************/

	/******************************************************************************************/
	//								MEMBER FUNCTION IMPLEMENTATIONS							  //
	/******************************************************************************************/

	/**************************************************************************/
	/*	Function: 	cProcess												  */
	/*                                                                        */
	/*	Description: This is the constructor for the cProcess class.		  */
	/*                                                                        */
	/*	Return Type: None													  */
	/*                                                                        */
	/*	Parameters: None													  */
	/**************************************************************************/
	cProcess::cProcess()
	{
		// Simply clear all the memory of our variables
		handle = 0;
		hwnd = 0;
		ZeroMemory(&pe32, sizeof(PROCESSENTRY32));

		// This is a must in Win32 for this struct!
		pe32.dwSize = sizeof(PROCESSENTRY32);
	}

	/**************************************************************************/
	/*	Function: 	cProcess												  */
	/*                                                                        */
	/*	Description: This is the destructor for the cProcess class.			  */
	/*                                                                        */
	/*	Return Type: None													  */
	/*                                                                        */
	/*	Parameters: None													  */
	/**************************************************************************/
	cProcess::~cProcess()
	{
		// Call the Close function on object destruction
		Close();
	}

	/**************************************************************************/
	/*	Function: Open														  */
	/*                                                                        */
	/*	Description: This function will open the desired executable's process.*/
	/*	Since there could be many processes with the same executable, a		  */
	/*	feature exsits to help the user select the correct window. The hwnd is*/
	/*	activated and the user replies to a message box as to if it is correct*/
	/*                                                                        */
	/*	Return Type: bool: true = success, false = failure					  */
	/*                                                                        */
	/*	Parameters:															  */
	/*		const string& exeName - This parameter is the executable file of  */
	/*								the process we with to open.			  */
	/*		bool lookForWindow -	Should the class find the main HWND		  */ 
	/*								[Default: true]							  */
	/*		DWORD dwDesiredAccess - This is the optional desired access flag  */
	/*								used to open the process.				  */
	/*								[Default: PROCESS_ALL_ACCESS]			  */
	/*		BOOL bInhereitHandle -  This is the optional desired flag used to */
	/*							    open the  process						  */
	/*								[Default: FALSE]                          */
	/**************************************************************************/
	bool Open(const std::string& exeName, bool lookForWindow = true, DWORD dwDesiredAccess = PROCESS_ALL_ACCESS, BOOL bInhereitHandle = FALSE)
	{
		/****************************************/
		/* First see if we can find the process */
		/****************************************/
		
		// Used to get our process snapshot
		HANDLE hProcessSnap = 0;

		// Current operating status
		bool status = false;

		// First wee if we can get a snapshot of all processes
		if((hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) == INVALID_HANDLE_VALUE)
		{
			// If we cant, return false for failure
			return false;
		}

		// If we were able to get the snapshot, call the Close function in case this particular
		// Process object was already opened.
		Close();

		// Retrieve the information about the first process encountered in the system snapshot
		if(Process32First(hProcessSnap, &pe32))
		{
			// Now get ready to loop though all of the processes
			do
			{
				// First check to see if the exe file name matches the one we are looking for
				if(std::string(pe32.szExeFile) == exeName)
				{
					// If we should find the window for this process
					if(lookForWindow)
					{
						// Now we call the enumCallbackFunc in order to find the 
						// main HWND associated with the process. Note that a process could
						// have more than one HWND, so this library just gets the first. We
						// pass 'this' current object to the function in order to be able to
						// assign the HWND back to this class object.
						EnumWindows(enumCallbackFunc, (LPARAM)this);

						// If the hwnd is not null, then we have found the main window and 
						// no longer need to continue this loop
						if(hwnd)
						{
							status = true;
						}
					}
					else
					{
						// Otherwise if there is no window being looked for, 
						// we take the first process we find
						status = true;
					}
				}
			}
			// For our do-while we will loop while the HWND was not found and we have another process to check
			while(!status && Process32Next(hProcessSnap, &pe32));
		}
		else
		{
			// If we reach this part there was a major error because Process32First has failed 
			ShowError("cProcess::Open - Process32First");
			return false;
		}

		// Once we get here, we no longer need the snapshot because we looked though all the processes
		CloseHandle(hProcessSnap);

		// Now, we will check if we found the process or not. We set status to true above to indicate if we did
		if(!status)
		{
			return false;
		}

		/****************************************/
		/* If we found it, now we can open it   */
		/****************************************/

		// Now we will try to open the process and store it
		handle = OpenProcess(dwDesiredAccess, bInhereitHandle, pe32.th32ProcessID);
		if(!handle)
		{
			// If we reach this part there was a problem because we could not open our process
			ShowError("cProcess::Open - OpenProcess");
			return false;
		}

		// If we get here, we have found our process and hwnd and are ready to use the clas object!
		return true;
	}

	/**************************************************************************/
	/*	Function: Close														  */
	/*                                                                        */
	/*	Description: This function will close the opened process.			  */
	/*                                                                        */
	/*	Return Type: None													  */
	/*                                                                        */
	/*	Parameters: None													  */
	/**************************************************************************/
	void Close()
	{
		// First we will want to see if the handle we have is valid and close it
		if(handle && CloseHandle(handle) != 0)
		{
			handle = 0;
		}

		// Next just clear out our variables
		ZeroMemory(&pe32, sizeof(PROCESSENTRY32));
		pe32.dwSize = sizeof(PROCESSENTRY32);
		hwnd = 0;
	}

	/**************************************************************************/
	/*	Function: Read														  */
	/*                                                                        */
	/*	Description: This function will read exactly 'one' unit of the passed */
	/*				 datatype specified.									  */
	/*                                                                        */
	/*	Return Type: bool: true = success, false = failure					  */
	/*                                                                        */
	/*	Parameters:															  */
	/*		unsigned long address - The address of the memory to read.		  */
	/*		type& buffer - The variable to store the read memory to.	      */
	/**************************************************************************/
	template <class type>
	bool Read(unsigned long address, type& buffer)
	{
		// Holds the number of bytes read
		SIZE_T read = 0;
		// Try to read the memory and if there was a problem, show the error
		if(!ReadProcessMemory(handle, (LPCVOID)address, (LPVOID)&buffer, sizeof(type), &read))
		{
			ShowError("cProcess::Read - ReadProcessMemory");
			return false;
		}
		// Success! buffer now contains the memory read.
		return true;
	}

	/**************************************************************************/
	/*	Function: ReadArray													  */
	/*                                                                        */
	/*	Description: This function will read exactly sizeOfBuffer units of the*/
	/*				 passed datatype specified or until 'stopValue' is read.  */
	/*                                                                        */
	/*	Return Type: bool: true = success, false = failure					  */
	/*                                                                        */
	/*	Parameters:															  */
	/*		unsigned long address - The address of the memory to read.		  */
	/*		type* buffer - The array of variables to store the read memory to.*/
	/*		int sizeOfBuffer - The number of elements the array has	space for */
	/*		type stopValue - The value to signal to stop reading memory if    */
	/*			             the number of elements read is smaller than      */
	/*						 sizeOfBuffer.                                    */
	/**************************************************************************/
	template <class type>
	bool ReadArray(unsigned long address, type* buffer, int sizeOfBuffer, type stopValue)
	{
		// Holds the number of bytes read
		SIZE_T read = 0;
		// Precalcuate and store the size of the data type being used
		SIZE_T dataSize = sizeof(type);

		// Loop though all of the elements in the array and fill them in
		for(int x = 0; x < sizeOfBuffer; ++x)
		{
			// Try to read the memory and if there was a problem, show the error
			if(!ReadProcessMemory(handle, (LPCVOID)(address + (dataSize * x)), (LPVOID)&buffer[x], dataSize, &read))
			{
				ShowError("cProcess::ReadArray - ReadProcessMemory");
				// We shouldn't try to continue
				return false;
			}
			// Check to see if the current value read in is our stop value, if so, we are done
			if(buffer[x] == stopValue)
			{
				// Success!
				return true;
			}
		}
		// Success!
		return true;
	}

	/**************************************************************************/
	/*	Function: ReadArray													  */
	/*                                                                        */
	/*	Description: This function will read exactly sizeOfBuffer units of the*/
	/*				 passed datatype specified.								  */
	/*                                                                        */
	/*	Return Type: bool: true = success, false = failure					  */
	/*                                                                        */
	/*	Parameters:															  */
	/*		unsigned long address - The address of the memory to read.		  */
	/*		type* buffer - The array of variables to store the read memory to.*/
	/*		int sizeOfBuffer - The number of elements the array has	space for.*/
	/**************************************************************************/
	template <class type>
	bool ReadArray(unsigned long address, type* buffer, int sizeOfBuffer)
	{
		// Holds the number of bytes read
		SIZE_T read = 0;
		// Precalcuate and store the size of the data type being used
		SIZE_T dataSize = sizeof(type);

		// Loop though all of the elements in the array and fill them in
		for(int x = 0; x < sizeOfBuffer; ++x)
		{
			// Try to read the memory and if there was a problem, show the error
			if(!ReadProcessMemory(handle, (LPCVOID)(address + (dataSize * x)), (LPVOID)&buffer[x], dataSize, &read))
			{
				return false;
			}
		}
		// Success!
		return true;
	}

	/**************************************************************************/
	/*	Function: Write														  */
	/*                                                                        */
	/*	Description: This function will write the passed variable to memory.  */
	/*                                                                        */
	/*	Return Type: bool: true = success, false = failure					  */
	/*                                                                        */
	/*	Parameters:															  */
	/*		unsigned long address - The address of the memory to read.		  */
	/*		type& buffer - The variable to store in memory.					  */
	/**************************************************************************/
	template <class type>
	bool Write(unsigned long address, type& buffer)
	{
		// Holds the number of bytes written
		SIZE_T write = 0;

		// Try to write the memory and if there was a problem, show the error and return a failure
		if(!WriteProcessMemory(handle, (LPVOID)address, (LPVOID)&buffer, sizeof(type), &write))
		{
			ShowError("cProcess::Write - WriteProcessMemory");
			return false;
		}
		// Success!
		return true;
	}

	/**************************************************************************/
	/*	Function: WriteArray												  */
	/*                                                                        */
	/*	Description: This function will write the buffer of passed datatype   */
	/*				 specified into the memory address specificed.			  */
	/*                                                                        */
	/*	Return Type: bool: true = success, false = failure					  */
	/*                                                                        */
	/*	Parameters:															  */
	/*		unsigned long address - The address of the memory to read.		  */
	/*		type* buffer - The array of variables to write into memory.		  */
	/*		int sizeOfBuffer - The number of elements the array has.		  */
	/**************************************************************************/
	template <class type>
	bool WriteArray(unsigned long address, type* buffer, int sizeOfBuffer)
	{
		// Holds the number of bytes written
		SIZE_T write = 0;
		// Precalcuate and store the size of the data type being used
		SIZE_T dataSize = sizeof(type);

		// Loop though all of the elements in the array and fill memory with them
		for(int x = 0; x < sizeOfBuffer; ++x)
		{
			// Try to write the memory and if there was a problem, show the error
			if(!WriteProcessMemory(handle, (LPVOID)(address + (dataSize * x)), (LPVOID)&buffer[x], dataSize, &write))
			{
				ShowError("cProcess::WriteArray - WriteProcessMemory");
				// We shouldn't try to continue
				return false;
			}
		}
		// Success!
		return true;
	}
};

// Taken and modified from a MSDN example, it will present a messagebox 
// to the user with the current error. Dont worry about this function.
void ShowError(LPTSTR lpszFunction) 
{ 
	LPVOID lpMsgBuf;
	LPVOID lpDisplayBuf;
	DWORD dw = GetLastError(); 
	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL );
	lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR)); 
	wsprintf((LPTSTR)lpDisplayBuf, TEXT("%s failed with error %d: %s"), lpszFunction, dw, lpMsgBuf);
	MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK | MB_ICONERROR); 
	LocalFree(lpMsgBuf);
	LocalFree(lpDisplayBuf);
}

// This function is the callback function used for EnumWindows
BOOL CALLBACK enumCallbackFunc(HWND hwnd, LPARAM lparam)
{
	// Since we passed the cProcess object we are working on, first retrieve it
	cProcess* process = (cProcess*)lparam;

	// Holds the process id of the window we are looking at
	DWORD pid = 0;

	// Get the process id
	GetWindowThreadProcessId(hwnd, &pid);

	// If the cProcess object's id equals the windows id
	if(process->pe32.th32ProcessID == pid)
	{
		// Store the active window
		HWND active = ::GetForegroundWindow();

		// Bring the window we are looking at to the top
		SetForegroundWindow(hwnd);

		// Check with the user as to if this is the right window
		if(MessageBox(hwnd, "Was the correct window activated?", "Desired Window?", MB_ICONQUESTION | MB_YESNO) == IDYES)
		{
			// If so, save the hwnd to the class object
			process->hwnd = hwnd;

			// Restore the old foreground window
			SetForegroundWindow(active);

			// Return false so we do not call this function anymore, we are done
			return FALSE;
		}
		else
		{
			// Otherwise simply restore the old foreground window 
			SetForegroundWindow(active);
		}
	}

	// Return true to keep on going though windows
	return TRUE;
}

#endif
Remember the code is over 2 years old now and the setup of the program reflects not knowing too much about setting up programs in an easy to use and modify way lol. Anyways it should be enough to get the idea of what to do.

Here is what the process looks like after you compile and run.



Just sharing because I did this a long time ago. I'm not going to maintain the project or rerelease it again since I've got enough stuff I'm working on. Feel free to compile and play with it though.
pushedx is offline  
Thanks
6 Users
Old 08/08/2009, 21:41   #3
 
urmomzzz's Avatar
 
elite*gold: 20
Join Date: Jul 2008
Posts: 1,199
Received Thanks: 362
I doubt he will even read half of what you wrote... But GJ anyways
urmomzzz is offline  
Old 06/18/2012, 02:44   #4
 
elite*gold: 0
Join Date: May 2012
Posts: 3
Received Thanks: 0
Quote:
Originally Posted by pushedx View Post
I wrote code to do it a long time ago. The first way I did it was to perform client edits via WriteProcessMemory through a secondary program. That would work for all chat types except for All Chat right now due to how the client code is setup.

The second method I used was to create a codecave in the client to process the chat color logic. You can get the current chat type and then specify a custom color for it. That is much easier to work with, but requires the use of a loader and injected DLL. You could use my guides to do it though but I'm not going to myself.

Here's the code in the latest 205 client that has to deal with chat colors.

Code:
007A37C7   .  8078 04 00    CMP BYTE PTR DS:[EAX+4],0
007A37CB   .^ 0F84 B2FEFFFF JE sro_clie.007A3683
007A37D1   >  BD FEFF9FFF   MOV EBP,FF9FFFFE                         ;  Case A of switch 007A37B3
007A37D6   .  EB 34         JMP SHORT sro_clie.007A380C
007A37D8   >  BD 00FFFFFF   MOV EBP,-100                             ;  Case 6 of switch 007A37B3
007A37DD   .  EB 2D         JMP SHORT sro_clie.007A380C
007A37DF   >  BD C3AEFFFF   MOV EBP,FFFFAEC3                         ;  Cases 3,7 of switch 007A37B3
007A37E4   .  EB 26         JMP SHORT sro_clie.007A380C
007A37E6   >  BD 41B5FFFF   MOV EBP,FFFFB541                         ;  Case 5 of switch 007A37B3
007A37EB   .  EB 1F         JMP SHORT sro_clie.007A380C
007A37ED   >  BD 73F5C2FF   MOV EBP,FFC2F573                         ;  Case B of switch 007A37B3
007A37F2   .  EB 18         JMP SHORT sro_clie.007A380C
007A37F4   >  BD D0FF9AFF   MOV EBP,FF9AFFD0                         ;  Case 4 of switch 007A37B3
007A37F9   .  EB 11         JMP SHORT sro_clie.007A380C
007A37FB   >  BD F8ADDBFF   MOV EBP,FFDBADF8                         ;  Case D of switch 007A37B3
007A3800   .  EB 0A         JMP SHORT sro_clie.007A380C
007A3802   >  BD FFC764FF   MOV EBP,FF64C7FF                         ;  Case 10 of switch 007A37B3
007A3807   .  EB 03         JMP SHORT sro_clie.007A380C
007A3809   >  83CD FF       OR EBP,FFFFFFFF                          ;  Default case of switch 007A37B3
007A380C   >  B8 07000000   MOV EAX,7
You should be able to follow the colors in a graphics program that allows you to use hex/decimal for RGB. The colors are stored backwards in memory so FEFF9FFF is color (ARGB) FF 9F FF FE, or the color for whisper chat.

Here's the updated code to the project I wrote back in Feb. 07. The concept is pretty simple. Just write out the new hex values for the colors in the Silkroad process. You need to be running the program in Administrator in Vista/Win7 as well.

SilkroadChatColor.cpp
Code:
#include "cProcess.h"

#include <windows.h>
#include <math.h>
#include <stdio.h>
#include <fstream>
#include <sstream>

// Main program window
HWND hwnd = 0;

// Array of addresses to make for easier access
unsigned long addrs[6];
unsigned long defs[6];
unsigned long curs[6];
HWND hwnds[6];
HWND preview[6];

// Whisper
HWND lblWhisper = 0;
HWND editWhisper = 0;
HWND btnDefWhisper = 0;
unsigned long addrWhisper = 0x7A37D1;
unsigned long defColorWhisper = 0xFF9FFFFE;

// Global
HWND lblGlobal = 0;
HWND editGlobal = 0;
HWND btnDefGlobal = 0;
unsigned long addrGlobal = 0x7A37D8;
unsigned long defColorGlobal = 0xFFFFFF00;

// Notice
HWND lblNotice = 0;
HWND editNotice = 0;
HWND btnDefNotice = 0;
unsigned long addrNotice = 0x7A37DF;
unsigned long defColorNotice = 0xFFFFAEC3;

// Guild
HWND lblGuild = 0;
HWND editGuild = 0;
HWND btnDefGuild = 0;
unsigned long addrGuild = 0x7A37E6;
unsigned long defColorGuild = 0xFFFFB541;

// Union
HWND lblUnion = 0;
HWND editUnion = 0;
HWND btnDefUnion = 0;
unsigned long addrUnion = 0x7A37ED;
unsigned long defColorUnion = 0xFFC2F573;

// Party
HWND lblParty = 0;
HWND editParty = 0;
HWND btnDefParty = 0;
unsigned long addrParty = 0x7A37F4;
unsigned long defColorParty = 0xFF9AFFD0;

// Set chat color button
HWND btnColorize = 0;
HWND btnPerm = 0;

// Get the current color a chat type
HWND btnGetWhisper = 0;
HWND btnGetGlobal = 0;
HWND btnGetNotice = 0;
HWND btnGetGuild = 0;
HWND btnGetUnion = 0;
HWND btnGetParty = 0;
HWND btnGetAll = 0;

// Defines for the button messages
#define BTN_DEF_COLOR_WHISPER	1
#define BTN_DEF_COLOR_GLOBAL	2
#define BTN_DEF_COLOR_NOTICE	3
#define BTN_DEF_COLOR_GUILD		4
#define BTN_DEF_COLOR_UNION		5
#define BTN_DEF_COLOR_PARTY		6
#define BTN_DEF_COLOR_ALL		7
#define BTN_COLORIZE_ON			8
#define BTN_COLORIZE_GET		9


#define BTN_PREVIEW_COLOR_WHSIPER	11
#define BTN_PREVIEW_COLOR_GLOBAL	12
#define BTN_PREVIEW_COLOR_NOTICE	13
#define BTN_PREVIEW_COLOR_GUILD		14
#define BTN_PREVIEW_COLOR_UNION		15
#define BTN_PREVIEW_COLOR_PARTY		16
#define BTN_PREVIEW_COLOR_ALL		17

#define BTN_GET_COLOR_WHISPER	18
#define BTN_GET_COLOR_GLOBAL	19
#define BTN_GET_COLOR_NOTICE	20
#define BTN_GET_COLOR_GUILD		21
#define BTN_GET_COLOR_UNION		22
#define BTN_GET_COLOR_PARTY		23
#define BTN_GET_COLOR_ALL		24

// cProcess class object used to make working with processes a lot easier ;)
cProcess sro;

unsigned long CaptionToHex(HWND h)
{
	// Store the actual hex string
	unsigned char data[5] = {0};
	// Store the ascii-hex string
	char temp[32] = {0};
	// The alpha should be FF, opaque (don't think font supports alpha)
	temp[0] = 'F';
	temp[1] = 'F';
	// Get the desired window's color
	GetWindowText(h, temp + 2, 7);
	// Store the final value
	int value = 0;
	// We have to reverse the digits for hex form
	int index = 3;
	// Loop though all tuples of characters
	for(int y = 0; y < 8; y += 2)
	{
		int tuple1 = 15, tuple2 = 15;
		// Store current character
		unsigned char cur = temp[y];
		// If it's A - F, convert it to 10 - 15
		if(cur >= 'A' && cur <= 'F')
			tuple1 = cur - 'A' + 10;
		// If it's 0 - 9, convert it to 0 - 9
		else if(cur >= '0' && cur <= '9')
			tuple1 = cur - '0';

		// Store current character
		cur = temp[y + 1];
		// If it's A - F, convert it to 10 - 15
		if(cur >= 'A' && cur <= 'F')
			tuple2 = cur - 'A' + 10;
		// If it's 0 - 9, convert it to 0 - 9
		else if(cur >= '0' && cur <= '9')
			tuple2 = cur - '0';
		// Convert the two numbers into a unsigned character
		value = tuple2 + 16 * tuple1;
		// Store the final color value for this color component
		data[index--] = value;
	}
	// Store a pointer of the final color value as a unsigned long
	unsigned long* ptr = (unsigned long*)data;
	return *ptr;
}

void DrawColorPreview(HDC hdc, int x, int y, unsigned long color) 
{
	color = color & 0x00FFFFFF;
	HBRUSH NewBrush = CreateSolidBrush(RGB(GetBValue(color),GetGValue(color),GetRValue(color)));
	SelectObject(hdc, NewBrush);
	Rectangle(hdc, x, y, x + 18, y + 18);
	DeleteObject(NewBrush);
}

// Get the current chat colors
void GetCurrentChatColors(int x)
{
	// Array to hold the data
	unsigned char buffer[5] = {0};
	// Read in the memory location
	if(!sro.ReadArray(addrs[x], buffer, 5))
	{
		MessageBox(hwnd, "Memory address could not be read.", "Fatal Error", MB_OK | MB_ICONERROR);
		return;
	}
	char temp[256] = {0};
	// Store the color components into the array
	_snprintf(temp, 255, "%.2X%.2X%.2X", buffer[3], buffer[2], buffer[1]);
	// Write the entire RGB color string to the edit box
	SetWindowText(hwnds[x], temp);
}

void GeneratePreview(HWND btn, int button)
{
	curs[button] = CaptionToHex(btn);
	RECT r;
	r.left = 284;
	r.right = r.left + 18;
	r.top = 10 + button * 30;
	r.bottom = r.top + 18;
	InvalidateRect(hwnd, &r, true);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT Ps;
	HDC hdc;
	switch(msg)
	{
	case WM_PAINT:
		{
			hdc = BeginPaint(hwnd, &Ps);
			for(int x = 0; x < 6; ++x)
				DrawColorPreview(hdc, 284, 10 + x * 30, curs[x]);
			EndPaint(hwnd, &Ps);
		}
		break;

	case WM_COMMAND:
		{
			if(LOWORD(wParam) == BTN_COLORIZE_ON)
			{
				// Loop though all chat colors
				for(int x = 0; x < 6; ++x)
				{
					int ptr = CaptionToHex(hwnds[x]);
					// Write the color value to memory
					sro.Write(addrs[x] + 1, ptr);
				}
			}
			else if(LOWORD(wParam) >= BTN_GET_COLOR_WHISPER && LOWORD(wParam) <= BTN_GET_COLOR_ALL)
			{
				int button = LOWORD(wParam) - BTN_GET_COLOR_WHISPER;
				GetCurrentChatColors(button);
				GeneratePreview(hwnds[button], button);
			}
			else if(LOWORD(wParam) >= BTN_DEF_COLOR_WHISPER && LOWORD(wParam) <= BTN_DEF_COLOR_ALL)
			{
				// Save the real button #
				int button = LOWORD(wParam) - 1;
				// Buffer to hold the default value
				char temp[256] = {0};
				// Save the default value to the buffer
				sprintf(temp, "%X", defs[button]);
				// Write the default value to the window
				SetWindowText(hwnds[button], temp + 2);
				GeneratePreview(hwnds[button], button);
			}
			else if(LOWORD(wParam) >= BTN_PREVIEW_COLOR_WHSIPER && LOWORD(wParam) <= LOWORD(wParam))
			{
				int button = LOWORD(wParam) - BTN_PREVIEW_COLOR_WHSIPER;
				GeneratePreview(hwnds[button], button);
			}
		}
		break; 

	case WM_CLOSE:
		{
			DestroyWindow(hwnd);
		}
		break;

	case WM_DESTROY:
		{
			PostQuitMessage(0);
		}
		break;

	default:
		{
			return DefWindowProc(hwnd, msg, wParam, lParam);
		}
	}
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEX wc = {0};
	MSG msg = {0};

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WndProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = GetModuleHandle(0);
	wc.hIcon         = LoadIcon(NULL, MAKEINTRESOURCE(101));
	wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+6);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = "SROChatColor";
	wc.hIconSm       = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(101), IMAGE_ICON, 16, 16, 0);;

	// Win32 stuff to create the program
	if(!RegisterClassEx(&wc))
	{
		MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONERROR | MB_OK);
		return 0;
	}

	// Create main window
	hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "SROChatColor", "Silkroad Chat Color - By: Drew Benton", WS_OVERLAPPEDWINDOW ^ WS_MAXIMIZEBOX ^ WS_THICKFRAME, CW_USEDEFAULT, CW_USEDEFAULT, 480, 290, NULL, NULL, hInstance, NULL);
	if(hwnd == NULL)
	{
		MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONERROR | MB_OK);
		return 0;
	}

	// Try to open the sro client
	if(!sro.Open("sro_client.exe"))
	{
		MessageBox(0, "Cannot find your sro_client.exe", "Error!", MB_ICONERROR | MB_OK);
		return -1;
	}

	// Store the addresses
	addrs[0] = addrWhisper;
	addrs[1] = addrGlobal;
	addrs[2] = addrNotice;
	addrs[3] = addrGuild;
	addrs[4] = addrUnion;
	addrs[5] = addrParty;
	//addrs[6] = addrAll;

	// Store default colors
	defs[0] = defColorWhisper;
	defs[1] = defColorGlobal;
	defs[2] = defColorNotice;
	defs[3] = defColorGuild;
	defs[4] = defColorUnion;
	defs[5] = defColorParty;
	//defs[6] = defColorAll;

	// Store defaults
	for(int x = 0; x < 6; ++x)
		curs[x] = defs[x];

	// Coords of controls
	int X = 0; int Y = 0; int W = 0; int H = 0;

	// Whisper
	X = 10; Y = 10; W = 125; H = 20;
	lblWhisper = CreateWindowEx(0, "STATIC", "Whisper Chat: ", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 110;
	editWhisper = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 312; W = 70;
	btnDefWhisper = CreateWindowEx(0, "BUTTON", "Default", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_DEF_COLOR_WHISPER, NULL, 0);
	X = 392;
	btnGetWhisper = CreateWindowEx(0, "BUTTON", "Current", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_GET_COLOR_WHISPER, NULL, 0);
	X = 250; W = 24;
	preview[0] = CreateWindowEx(0, "BUTTON", "?", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_PREVIEW_COLOR_WHSIPER, NULL, 0);

	// Global
	X = 10; Y = 40; W = 125; H = 20;
	lblGlobal = CreateWindowEx(0, "STATIC", "Global Chat: ", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 110;
	editGlobal = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 312; W = 70;
	btnDefWhisper = CreateWindowEx(0, "BUTTON", "Default", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_DEF_COLOR_GLOBAL, NULL, 0);
	X = 392;
	btnGetGlobal = CreateWindowEx(0, "BUTTON", "Current", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_GET_COLOR_GLOBAL, NULL, 0);
	X = 250; W = 24;
	preview[1] = CreateWindowEx(0, "BUTTON", "?", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_PREVIEW_COLOR_GLOBAL, NULL, 0);

	// Notice
	X = 10; Y = 70; W = 125; H = 20;
	lblNotice = CreateWindowEx(0, "STATIC", "Notice Chat: ", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 110;
	editNotice = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 312; W = 70;
	btnDefNotice = CreateWindowEx(0, "BUTTON", "Default", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_DEF_COLOR_NOTICE, NULL, 0);
	X = 392;
	btnGetNotice = CreateWindowEx(0, "BUTTON", "Current", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_GET_COLOR_NOTICE, NULL, 0);
	X = 250; W = 24;
	preview[2] = CreateWindowEx(0, "BUTTON", "?", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_PREVIEW_COLOR_NOTICE, NULL, 0);

	// Guild
	X = 10; Y = 100; W = 125; H = 20;
	lblGuild = CreateWindowEx(0, "STATIC", "Guild Chat: ", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 110;
	editGuild = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 312; W = 70;
	btnDefGuild = CreateWindowEx(0, "BUTTON", "Default", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_DEF_COLOR_GUILD, NULL, 0);
	X = 392;
	btnGetGuild = CreateWindowEx(0, "BUTTON", "Current", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_GET_COLOR_GUILD, NULL, 0);
	X = 250; W = 24;
	preview[3] = CreateWindowEx(0, "BUTTON", "?", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_PREVIEW_COLOR_GUILD, NULL, 0);

	// Union
	X = 10; Y = 130; W = 125; H = 20;
	lblUnion = CreateWindowEx(0, "STATIC", "Union Chat: ", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 110;
	editUnion = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 312; W = 70;
	btnDefUnion = CreateWindowEx(0, "BUTTON", "Default", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_DEF_COLOR_UNION, NULL, 0);
	X = 392;
	btnGetUnion = CreateWindowEx(0, "BUTTON", "Current", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_GET_COLOR_UNION, NULL, 0);
	X = 250; W = 24;
	preview[4] = CreateWindowEx(0, "BUTTON", "?", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_PREVIEW_COLOR_UNION, NULL, 0);

	// Party
	X = 10; Y = 160; W = 125; H = 20;
	lblParty = CreateWindowEx(0, "STATIC", "Party Chat: ", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 110;
	editParty = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER, X, Y, W, H, hwnd, NULL, NULL, 0);
	X = 312; W = 70;
	btnDefParty = CreateWindowEx(0, "BUTTON", "Default", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_DEF_COLOR_PARTY, NULL, 0);
	X = 392;
	btnGetParty = CreateWindowEx(0, "BUTTON", "Current", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_GET_COLOR_PARTY, NULL, 0);
	X = 250; W = 24;
	preview[5] = CreateWindowEx(0, "BUTTON", "?", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_PREVIEW_COLOR_PARTY, NULL, 0);

	// Set chat color button
	X = 312; Y = 220; W = 150; H = 30;
	btnColorize = CreateWindowEx(0, "BUTTON", "Change Chat Colors!", WS_CHILD | WS_VISIBLE, X, Y, W, H, hwnd, (HMENU)BTN_COLORIZE_ON, NULL, 0);

	// Store the edit handles to make life easier
	hwnds[0] = editWhisper;
	hwnds[1] = editGlobal;
	hwnds[2] = editNotice;
	hwnds[3] = editGuild;
	hwnds[4] = editUnion;
	hwnds[5] = editParty;
	//hwnds[6] = editAll;

	// Start the program out by getting the current colors stored in memory
	for(int x = 0; x < 6; ++x)
		GetCurrentChatColors(x);

		// Reactivate this program
	SetForegroundWindow(hwnd);

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

	while(msg.message != WM_QUIT)
	{
		if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			WaitMessage();
		}
	}
	return 0;
}
cProcess.h
Code:
/*****************************************************************************/
/* cProcess
/* By; Drew Benton
/*
/* This class was written to make working with processes a lot easier. With 
/* this class, the user will be able to open a process and read from memory
/* or write to memory. It is designed with simplicty and ease of use in mind.
/* If you have any questions or comments e-mail me at 
/*
/******************************************************************************/

#ifndef CPROCESS_H_
#define CPROCESS_H_

#include <windows.h>
#include <tlhelp32.h>
#include <string>

// Display the current error to the user via a message box
void ShowError(LPTSTR lpszFunction);

// The callback function used for processing HWNDs
BOOL CALLBACK enumCallbackFunc(HWND hwnd, LPARAM lparam);

class cProcess
{
public:
	// The process entry for the process
	PROCESSENTRY32 pe32;

	// Handle to the process
	HANDLE handle;

	// One of the HWNDs associated with the process
	HWND hwnd;

public:
	/******************************************************************************************/
	//								MEMBER FUNCTIONS REFERENCE								  //
	/******************************************************************************************/
	/*	// This is the constructor for the cProcess class.
	/*	cProcess();
	/*	// This is the destructor for the cProcess class.
	/*	~cProcess();
	/*
	/*	// This function will open the desired executable's process.
	/*	bool Open(
	/*		const std::string& exeName, 
	/*		bool lookForWindow = true,
	/*		DWORD dwDesiredAccess = PROCESS_ALL_ACCESS, 
	/*		BOOL bInhereitHandle = FALSE);
	/*
	/*	// This function will close the opened process.
	/*	void Close();
	/*
	/*	// This function will read exactly 'one' unit of the passed datatype specified.
	/*	template <class type> 
	/*	bool Read(
	/*		unsigned long address, 
	/*		type& buffer);
	/*
	/*	// This function will read exactly sizeOfBuffer units of the 
	/*	// passed datatype specified or until 'stopValue' is read.
	/*	template <class type>
	/*	bool ReadArray(
	/*		unsigned long address, 
	/*		type* buffer, 
	/*		int sizeOfBuffer, 
	/*		type stopValue);
	/*
	/*	// This function will read exactly sizeOfBuffer units of the passed datatype specified.
	/*	template <class type>
	/*	bool ReadArray(
	/*		unsigned long address, 
	/*		type* buffer, 
	/*		int sizeOfBuffer);
	/*
	/*	// This function will write the passed variable to memory.
	/*	template <class type>
	/*	bool Write(
	/*		unsigned long address, 
	/*		type& buffer);
	/*
	/*	// This function will write the buffer of passed datatype 
	/*	// specified into the memory address specificed.
	/*	template <class type>
	/*	bool WriteArray(
	/*		unsigned long address, 
	/*		type* buffer, 
	/*		int sizeOfBuffer);
	/*****************************************************************************************/

	/******************************************************************************************/
	//								MEMBER FUNCTION IMPLEMENTATIONS							  //
	/******************************************************************************************/

	/**************************************************************************/
	/*	Function: 	cProcess												  */
	/*                                                                        */
	/*	Description: This is the constructor for the cProcess class.		  */
	/*                                                                        */
	/*	Return Type: None													  */
	/*                                                                        */
	/*	Parameters: None													  */
	/**************************************************************************/
	cProcess::cProcess()
	{
		// Simply clear all the memory of our variables
		handle = 0;
		hwnd = 0;
		ZeroMemory(&pe32, sizeof(PROCESSENTRY32));

		// This is a must in Win32 for this struct!
		pe32.dwSize = sizeof(PROCESSENTRY32);
	}

	/**************************************************************************/
	/*	Function: 	cProcess												  */
	/*                                                                        */
	/*	Description: This is the destructor for the cProcess class.			  */
	/*                                                                        */
	/*	Return Type: None													  */
	/*                                                                        */
	/*	Parameters: None													  */
	/**************************************************************************/
	cProcess::~cProcess()
	{
		// Call the Close function on object destruction
		Close();
	}

	/**************************************************************************/
	/*	Function: Open														  */
	/*                                                                        */
	/*	Description: This function will open the desired executable's process.*/
	/*	Since there could be many processes with the same executable, a		  */
	/*	feature exsits to help the user select the correct window. The hwnd is*/
	/*	activated and the user replies to a message box as to if it is correct*/
	/*                                                                        */
	/*	Return Type: bool: true = success, false = failure					  */
	/*                                                                        */
	/*	Parameters:															  */
	/*		const string& exeName - This parameter is the executable file of  */
	/*								the process we with to open.			  */
	/*		bool lookForWindow -	Should the class find the main HWND		  */ 
	/*								[Default: true]							  */
	/*		DWORD dwDesiredAccess - This is the optional desired access flag  */
	/*								used to open the process.				  */
	/*								[Default: PROCESS_ALL_ACCESS]			  */
	/*		BOOL bInhereitHandle -  This is the optional desired flag used to */
	/*							    open the  process						  */
	/*								[Default: FALSE]                          */
	/**************************************************************************/
	bool Open(const std::string& exeName, bool lookForWindow = true, DWORD dwDesiredAccess = PROCESS_ALL_ACCESS, BOOL bInhereitHandle = FALSE)
	{
		/****************************************/
		/* First see if we can find the process */
		/****************************************/
		
		// Used to get our process snapshot
		HANDLE hProcessSnap = 0;

		// Current operating status
		bool status = false;

		// First wee if we can get a snapshot of all processes
		if((hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) == INVALID_HANDLE_VALUE)
		{
			// If we cant, return false for failure
			return false;
		}

		// If we were able to get the snapshot, call the Close function in case this particular
		// Process object was already opened.
		Close();

		// Retrieve the information about the first process encountered in the system snapshot
		if(Process32First(hProcessSnap, &pe32))
		{
			// Now get ready to loop though all of the processes
			do
			{
				// First check to see if the exe file name matches the one we are looking for
				if(std::string(pe32.szExeFile) == exeName)
				{
					// If we should find the window for this process
					if(lookForWindow)
					{
						// Now we call the enumCallbackFunc in order to find the 
						// main HWND associated with the process. Note that a process could
						// have more than one HWND, so this library just gets the first. We
						// pass 'this' current object to the function in order to be able to
						// assign the HWND back to this class object.
						EnumWindows(enumCallbackFunc, (LPARAM)this);

						// If the hwnd is not null, then we have found the main window and 
						// no longer need to continue this loop
						if(hwnd)
						{
							status = true;
						}
					}
					else
					{
						// Otherwise if there is no window being looked for, 
						// we take the first process we find
						status = true;
					}
				}
			}
			// For our do-while we will loop while the HWND was not found and we have another process to check
			while(!status && Process32Next(hProcessSnap, &pe32));
		}
		else
		{
			// If we reach this part there was a major error because Process32First has failed 
			ShowError("cProcess::Open - Process32First");
			return false;
		}

		// Once we get here, we no longer need the snapshot because we looked though all the processes
		CloseHandle(hProcessSnap);

		// Now, we will check if we found the process or not. We set status to true above to indicate if we did
		if(!status)
		{
			return false;
		}

		/****************************************/
		/* If we found it, now we can open it   */
		/****************************************/

		// Now we will try to open the process and store it
		handle = OpenProcess(dwDesiredAccess, bInhereitHandle, pe32.th32ProcessID);
		if(!handle)
		{
			// If we reach this part there was a problem because we could not open our process
			ShowError("cProcess::Open - OpenProcess");
			return false;
		}

		// If we get here, we have found our process and hwnd and are ready to use the clas object!
		return true;
	}

	/**************************************************************************/
	/*	Function: Close														  */
	/*                                                                        */
	/*	Description: This function will close the opened process.			  */
	/*                                                                        */
	/*	Return Type: None													  */
	/*                                                                        */
	/*	Parameters: None													  */
	/**************************************************************************/
	void Close()
	{
		// First we will want to see if the handle we have is valid and close it
		if(handle && CloseHandle(handle) != 0)
		{
			handle = 0;
		}

		// Next just clear out our variables
		ZeroMemory(&pe32, sizeof(PROCESSENTRY32));
		pe32.dwSize = sizeof(PROCESSENTRY32);
		hwnd = 0;
	}

	/**************************************************************************/
	/*	Function: Read														  */
	/*                                                                        */
	/*	Description: This function will read exactly 'one' unit of the passed */
	/*				 datatype specified.									  */
	/*                                                                        */
	/*	Return Type: bool: true = success, false = failure					  */
	/*                                                                        */
	/*	Parameters:															  */
	/*		unsigned long address - The address of the memory to read.		  */
	/*		type& buffer - The variable to store the read memory to.	      */
	/**************************************************************************/
	template <class type>
	bool Read(unsigned long address, type& buffer)
	{
		// Holds the number of bytes read
		SIZE_T read = 0;
		// Try to read the memory and if there was a problem, show the error
		if(!ReadProcessMemory(handle, (LPCVOID)address, (LPVOID)&buffer, sizeof(type), &read))
		{
			ShowError("cProcess::Read - ReadProcessMemory");
			return false;
		}
		// Success! buffer now contains the memory read.
		return true;
	}

	/**************************************************************************/
	/*	Function: ReadArray													  */
	/*                                                                        */
	/*	Description: This function will read exactly sizeOfBuffer units of the*/
	/*				 passed datatype specified or until 'stopValue' is read.  */
	/*                                                                        */
	/*	Return Type: bool: true = success, false = failure					  */
	/*                                                                        */
	/*	Parameters:															  */
	/*		unsigned long address - The address of the memory to read.		  */
	/*		type* buffer - The array of variables to store the read memory to.*/
	/*		int sizeOfBuffer - The number of elements the array has	space for */
	/*		type stopValue - The value to signal to stop reading memory if    */
	/*			             the number of elements read is smaller than      */
	/*						 sizeOfBuffer.                                    */
	/**************************************************************************/
	template <class type>
	bool ReadArray(unsigned long address, type* buffer, int sizeOfBuffer, type stopValue)
	{
		// Holds the number of bytes read
		SIZE_T read = 0;
		// Precalcuate and store the size of the data type being used
		SIZE_T dataSize = sizeof(type);

		// Loop though all of the elements in the array and fill them in
		for(int x = 0; x < sizeOfBuffer; ++x)
		{
			// Try to read the memory and if there was a problem, show the error
			if(!ReadProcessMemory(handle, (LPCVOID)(address + (dataSize * x)), (LPVOID)&buffer[x], dataSize, &read))
			{
				ShowError("cProcess::ReadArray - ReadProcessMemory");
				// We shouldn't try to continue
				return false;
			}
			// Check to see if the current value read in is our stop value, if so, we are done
			if(buffer[x] == stopValue)
			{
				// Success!
				return true;
			}
		}
		// Success!
		return true;
	}

	/**************************************************************************/
	/*	Function: ReadArray													  */
	/*                                                                        */
	/*	Description: This function will read exactly sizeOfBuffer units of the*/
	/*				 passed datatype specified.								  */
	/*                                                                        */
	/*	Return Type: bool: true = success, false = failure					  */
	/*                                                                        */
	/*	Parameters:															  */
	/*		unsigned long address - The address of the memory to read.		  */
	/*		type* buffer - The array of variables to store the read memory to.*/
	/*		int sizeOfBuffer - The number of elements the array has	space for.*/
	/**************************************************************************/
	template <class type>
	bool ReadArray(unsigned long address, type* buffer, int sizeOfBuffer)
	{
		// Holds the number of bytes read
		SIZE_T read = 0;
		// Precalcuate and store the size of the data type being used
		SIZE_T dataSize = sizeof(type);

		// Loop though all of the elements in the array and fill them in
		for(int x = 0; x < sizeOfBuffer; ++x)
		{
			// Try to read the memory and if there was a problem, show the error
			if(!ReadProcessMemory(handle, (LPCVOID)(address + (dataSize * x)), (LPVOID)&buffer[x], dataSize, &read))
			{
				return false;
			}
		}
		// Success!
		return true;
	}

	/**************************************************************************/
	/*	Function: Write														  */
	/*                                                                        */
	/*	Description: This function will write the passed variable to memory.  */
	/*                                                                        */
	/*	Return Type: bool: true = success, false = failure					  */
	/*                                                                        */
	/*	Parameters:															  */
	/*		unsigned long address - The address of the memory to read.		  */
	/*		type& buffer - The variable to store in memory.					  */
	/**************************************************************************/
	template <class type>
	bool Write(unsigned long address, type& buffer)
	{
		// Holds the number of bytes written
		SIZE_T write = 0;

		// Try to write the memory and if there was a problem, show the error and return a failure
		if(!WriteProcessMemory(handle, (LPVOID)address, (LPVOID)&buffer, sizeof(type), &write))
		{
			ShowError("cProcess::Write - WriteProcessMemory");
			return false;
		}
		// Success!
		return true;
	}

	/**************************************************************************/
	/*	Function: WriteArray												  */
	/*                                                                        */
	/*	Description: This function will write the buffer of passed datatype   */
	/*				 specified into the memory address specificed.			  */
	/*                                                                        */
	/*	Return Type: bool: true = success, false = failure					  */
	/*                                                                        */
	/*	Parameters:															  */
	/*		unsigned long address - The address of the memory to read.		  */
	/*		type* buffer - The array of variables to write into memory.		  */
	/*		int sizeOfBuffer - The number of elements the array has.		  */
	/**************************************************************************/
	template <class type>
	bool WriteArray(unsigned long address, type* buffer, int sizeOfBuffer)
	{
		// Holds the number of bytes written
		SIZE_T write = 0;
		// Precalcuate and store the size of the data type being used
		SIZE_T dataSize = sizeof(type);

		// Loop though all of the elements in the array and fill memory with them
		for(int x = 0; x < sizeOfBuffer; ++x)
		{
			// Try to write the memory and if there was a problem, show the error
			if(!WriteProcessMemory(handle, (LPVOID)(address + (dataSize * x)), (LPVOID)&buffer[x], dataSize, &write))
			{
				ShowError("cProcess::WriteArray - WriteProcessMemory");
				// We shouldn't try to continue
				return false;
			}
		}
		// Success!
		return true;
	}
};

// Taken and modified from a MSDN example, it will present a messagebox 
// to the user with the current error. Dont worry about this function.
void ShowError(LPTSTR lpszFunction) 
{ 
	LPVOID lpMsgBuf;
	LPVOID lpDisplayBuf;
	DWORD dw = GetLastError(); 
	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL );
	lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR)); 
	wsprintf((LPTSTR)lpDisplayBuf, TEXT("%s failed with error %d: %s"), lpszFunction, dw, lpMsgBuf);
	MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK | MB_ICONERROR); 
	LocalFree(lpMsgBuf);
	LocalFree(lpDisplayBuf);
}

// This function is the callback function used for EnumWindows
BOOL CALLBACK enumCallbackFunc(HWND hwnd, LPARAM lparam)
{
	// Since we passed the cProcess object we are working on, first retrieve it
	cProcess* process = (cProcess*)lparam;

	// Holds the process id of the window we are looking at
	DWORD pid = 0;

	// Get the process id
	GetWindowThreadProcessId(hwnd, &pid);

	// If the cProcess object's id equals the windows id
	if(process->pe32.th32ProcessID == pid)
	{
		// Store the active window
		HWND active = ::GetForegroundWindow();

		// Bring the window we are looking at to the top
		SetForegroundWindow(hwnd);

		// Check with the user as to if this is the right window
		if(MessageBox(hwnd, "Was the correct window activated?", "Desired Window?", MB_ICONQUESTION | MB_YESNO) == IDYES)
		{
			// If so, save the hwnd to the class object
			process->hwnd = hwnd;

			// Restore the old foreground window
			SetForegroundWindow(active);

			// Return false so we do not call this function anymore, we are done
			return FALSE;
		}
		else
		{
			// Otherwise simply restore the old foreground window 
			SetForegroundWindow(active);
		}
	}

	// Return true to keep on going though windows
	return TRUE;
}

#endif
Remember the code is over 2 years old now and the setup of the program reflects not knowing too much about setting up programs in an easy to use and modify way lol. Anyways it should be enough to get the idea of what to do.

Here is what the process looks like after you compile and run.



Just sharing because I did this a long time ago. I'm not going to maintain the project or rerelease it again since I've got enough stuff I'm working on. Feel free to compile and play with it though.

please i need this program is necessary
™AmeerKing™ is offline  
Old 06/18/2012, 05:49   #5

 
elite*gold: 260
Join Date: Aug 2008
Posts: 560
Received Thanks: 3,779
Quote:
Originally Posted by ™AmeerKing™ View Post
please i need this program is necessary
I'll reply here instead of the PM you sent me.

The source code for that program is in my post and in your quote. It's a pure Win32 API program, so it's a really simple project. You just have to make a new empty Win32 GUI application, then paste in the code to "main.cpp" then add "cProcess.h" to the project (also copy paste from the quote). The project should use a "Multi-Byte Character Set".

In order to get it to work on current versions of Silkroad, you have to go through and update all of the addresses for the chat colors. Since that code was written like 5 years ago, some of the new chat colors for different chat text are not supported. Further more there, might be issues with actually writing to process memory if XTrap or HackShield is enabled.

Finding the chat color logic in the client is still simple, just search for a color. This is the revelant code section in ISRO:
Code:
0090BFE3   .  8D70 FF       LEA ESI, DWORD PTR DS:[EAX-1]            ;  Switch (cases 2..10)
0090BFE6   .  83FE 0F       CMP ESI, 0F
0090BFE9   .  77 4E         JA SHORT sro_clie.0090C039
0090BFEB   .  FF24B5 3CC890>JMP NEAR DWORD PTR DS:[ESI*4+90C83C]
0090BFF2   >  E8 C973BEFF   CALL sro_clie.004F33C0                   ;  Case 2 of switch 0090BFE3
0090BFF7   .  8078 04 00    CMP BYTE PTR DS:[EAX+4], 0
0090BFFB   .^ 0F84 ABFEFFFF JE sro_clie.0090BEAC
0090C001   >  BD FEFF9FFF   MOV EBP, FF9FFFFE                        ;  Case A of switch 0090BFE3
0090C006   .  EB 34         JMP SHORT sro_clie.0090C03C
0090C008   >  BD 00FFFFFF   MOV EBP, -100                            ;  Case 6 of switch 0090BFE3
0090C00D   .  EB 2D         JMP SHORT sro_clie.0090C03C
0090C00F   >  BD C3AEFFFF   MOV EBP, FFFFAEC3                        ;  Cases 3,7 of switch 0090BFE3
0090C014   .  EB 26         JMP SHORT sro_clie.0090C03C
0090C016   >  BD 41B5FFFF   MOV EBP, FFFFB541                        ;  Case 5 of switch 0090BFE3
0090C01B   .  EB 1F         JMP SHORT sro_clie.0090C03C
0090C01D   >  BD 73F5C2FF   MOV EBP, FFC2F573                        ;  Case B of switch 0090BFE3
0090C022   .  EB 18         JMP SHORT sro_clie.0090C03C
0090C024   >  BD D0FF9AFF   MOV EBP, FF9AFFD0                        ;  Case 4 of switch 0090BFE3
0090C029   .  EB 11         JMP SHORT sro_clie.0090C03C
0090C02B   >  BD F8ADDBFF   MOV EBP, FFDBADF8                        ;  Case D of switch 0090BFE3
0090C030   .  EB 0A         JMP SHORT sro_clie.0090C03C
0090C032   >  BD FFC764FF   MOV EBP, FF64C7FF                        ;  Case 10 of switch 0090BFE3
0090C037   .  EB 03         JMP SHORT sro_clie.0090C03C
0090C039   >  83CD FF       OR EBP, FFFFFFFF                         ;  Default case of switch 0090BFE3
0090C03C   >  B8 07000000   MOV EAX, 7
Any place with a "MOV EBP, #" line is the client loading the color for that specific type of chat. For all chat, white, 0xFFFFFF is used by masking the entire color value. All this means is that if you want to change all chat, you have to use a codecave or some other method of fitting in a "mov ebp, new color #" instruction in.

Rather than use my program, you can just edit the client's colors another way though. I did a quick test with one color and it still works, but there's better ways to go about this nowadays I guess.

Test image:
pushedx is offline  
Thanks
1 User
Old 07/31/2012, 20:19   #6
 
elite*gold: 0
Join Date: May 2012
Posts: 3
Received Thanks: 0
I'm sorry but the program does not work with me on the client vsro

Please tell me how to change the color of the chat client vsro by hex

I do not understand in the reverse engineering

™AmeerKing™ is offline  
Reply


Similar Threads Similar Threads
Flashy Chat Color Text
08/23/2009 - Aion Guides & Strategies - 4 Replies
=result will be >>> Hello! (1) End code to finish. http://i297.photobucket.com/albums/mm228/Wickelle n/colortexts.jpg 1 1 1 =========White 1 0 0 =========Red 0 1 0 =========Darkgreen
WoW Color Hack (Use color-codes in text)
09/23/2007 - WoW Exploits, Hacks, Tools & Macros - 31 Replies
WoWColorHack.flt -=Preamble=- I'm quite surprised that no one has released anything similar yet - the theory behind this dates back to the alpha days. Hell, I first used this filter on my own alpha sandbox. -=Theory=-



All times are GMT +1. The time now is 23:12.


Powered by vBulletin®
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2026 elitepvpers All Rights Reserved.