Problem z czytaniem pamięci (std::string)

Problem z czytaniem pamięci (std::string)
TheAifam5
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 6 lat
  • Postów:127
0

Witam. Mam problem... Otóż po zakończeniu programu dostaje:

Kopiuj
First-chance exception at 0x0FA0CCC8 (msvcp110d.dll) in XXX.exe: 0xC0000005: Access violation reading location 0x65746E49.
Unhandled exception at 0x0FA0CCC8 (msvcp110d.dll) in XXX.exe: 0xC0000005: Access violation reading location 0x65746E49.

Kod main.cpp: http://pastebin.com/X2NSwYDT

Otóż gdy zmienię na "char" (jednobajtowy), to dostaję pierwszą litere.. ale co robię źle z std::string?

//EDIT:
Dobra, udało mi się odczytać wartość przy użyciu "char".. ale wolałbym robić wszystkie przy użyciu std::String... Jak na razie jestem w kropce.. :/

//EDIT2:
Albo, mógłby ktoś mi pomóc w odczytywaniu danych z adresów?

PS: Naprawcie link do rejestracji (aktualnie: http://4programmers.net/Rejetracja i otrzymuję 404) z linku: http://4programmers.net/Forum/C_i_C++?mode=submit


Wole programowac niz spac :)
edytowany 2x, ostatnio: TheAifam5
fasadin
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
  • Postów:4882
0
  1. robisz new, nie robisz delete
  2. char to jeden znak (jak sama nazwa wskazuje z "angielska")
  3. pokaż plik Memory.h (ponieważ nie wiem czemu na stałe wpisujesz ten adres 0x00ACD6B0)
  4. poczytaj o operatorach to dostaniesz adres danej zmiennej
TheAifam5
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 6 lat
  • Postów:127
0

Wole programowac niz spac :)
CN
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 9 lat
  • Postów:38
1

Nie zrobisz tego z std::string, bo ten typ dynamicznie alokuje pamięć pod to co ma przechowywać.

TheAifam5
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 6 lat
  • Postów:127
0

Dzięki za wyjaśnienie ;) A jest jakaś inna biblioteka lub klasa przy której mogę to zrobić..? Oprócz "char". Tak żebym mógł odczytać wartość z adresu.... np : "Test"..


Wole programowac niz spac :)
edytowany 1x, ostatnio: TheAifam5
CN
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 9 lat
  • Postów:38
4

Bądź mężczyzną i zrób to jak mężczyzna na tablicy char.

msm
Rotfl ;]. Ale fakt jest faktem że masz rację (a ReadProcessMemory do stringa (??) to barbarzyństwo)...
TheAifam5
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 6 lat
  • Postów:127
0

Dobrze.. Będę mężczyzną i zrobię to jak prawdziwy mężczyzna "na tablicy char" :D


Wole programowac niz spac :)
TheAifam5
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 6 lat
  • Postów:127
0

Heh, podzielę się z Wami moim kodem ;)

Memory.cpp

Kopiuj
#include "Memory.h"

Memory::Memory(const char* ClassName)
{
	this->h_HWND = FindWindow(ClassName, NULL);
	GetWindowThreadProcessId(this->h_HWND, &this->h_PID);
	this->h_Process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, this->h_PID);
}

Memory::~Memory(void)
{
	this->h_HWND = NULL;
	this->h_PID = NULL;

	if (this->h_Process != 0x00000000)
		CloseHandle(this->h_Process);
}

Memory.h

Kopiuj
#pragma once

class Memory
{
public:
	Memory(const char* ClassName);
	template <class T> bool Read(unsigned int Offset, T& Value)
	{
		SIZE_T size = 1024;
		SIZE_T sizeRead;
		bool valid;

		valid = ReadProcessMemory(this->h_Process, (LPCVOID)Offset, (LPVOID)&Value, size, &sizeRead) ? true : false;

		if(valid == false || sizeRead != size){
			return false;
		}

		return true;
	}
	virtual ~Memory(void);
private:
	HANDLE h_Process;
	DWORD h_PID;
	HWND h_HWND;
};

//EDIT:
Pracuje jeszcze nad zapisywaniem :D

Pozdro, Mateusz ;)


Wole programowac niz spac :)
edytowany 3x, ostatnio: TheAifam5
Patryk27
ReadProcessMemory zwraca bool, więc po co dodatkowo komplikujesz sprawę?
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
1
  1. Memory::Memory - brak obsługi błędów, czyżby przez to że obawiasz się wyjątków w konstruktorze?

W wypadku wyjątku w konstruktorze destruktor AFAIK się nie uruchomi, więc masz trzy wyjścia:
a) rozdzielić konstruktor na konstruktor który tylko zapamiętuje parametry i wychodzi oraz na inicjalizator ("init", "attach") który robi resztę.
b) obsłużyć pobrane już w konstruktorze zasoby przez smart pointery:
http://www.parashift.com/c++-faq-lite/selfcleaning-members.html

c) przed rzuceniem wyjątkiem w konstruktorze zwolnić wszystko co było zaalokowane

  1. W wypadku błędu OpenProcess zwraca NULL. Dlaczego w destruktorze używasz jakiejś dziwnej stałej zamiast NULL?

  2. W Memory::Read zamiast:

Kopiuj
if(valid == false || sizeRead != size){

napisz:

Kopiuj
if((!valid) || sizeRead != size){	
edytowany 1x, ostatnio: vpiotr
TheAifam5
Wybrałbym przez smart pointery ale nie potrafię jeszcze sie z nimi bawić :/ Mam boost-a 1.51.0, może użyć jego do smart pointerów?
TheAifam5
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 6 lat
  • Postów:127
0

Sry... Ucze się jeszcze C++...
Mam kod:

Kopiuj
template <class T> bool Write(unsigned int Offset, const T* Value)
	{
		SIZE_T size = strlen(Value);

		SIZE_T sizeRead;
		bool valid;

		valid = WriteProcessMemory(this->h_Process, (LPVOID)Offset, (LPCVOID)&Value, size, &sizeRead);

		if((!valid) || sizeRead != size){
			std::cout << "Błąd" << std::endl;
			return false;
		}

		return true;

Ale chce by był on uniwersalny... na razie mam problem z tym. "Write<int>(0x0000001, 5665)" lub "Write<char>(0x0000001, "costam")". A dokładnie tu: "SIZE_T size = strlen(Value);"
Pomożecie? :)


Wole programowac niz spac :)
CN
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 9 lat
  • Postów:38
0

strlen jak sama nazwa wskazuje, zwraca długość ciągu znaków. Nie ma szans żeby to zastosować do liczb.
http://www.java2s.com/Tutorial/Cpp/0100__Development/Usingtypeidwithtemplates.htm
Jeśli typ to ciąg znaków użyj strlen, jeśli nie sizeof.

RE
Moderator
  • Rejestracja:około 18 lat
  • Ostatnio:12 miesięcy
2

Napisałem też podobną klasę. Używa inteligentnych wskaźników z C++11 oraz boost do przeładowania funkcji na podstawie typu szablonowego. Jeżeli nie chcesz bawić się w C++11 to inteligentne wskaźniki też można zamienić na te z boost.

Klasy używa się bardzo prosto i cała magia to metody Read oraz Write.

Write ma trzy wersje. Pierwsza jest podstawowa, przyjmuje adres docelowy, adres źródłowy oraz ilość bajtów do zapisania.
Druga wersja służy do zapisywania pojedynczych obiektów. Przyjmuje adres docelowy i referencję do obiektu.
Trzecia wersja służy do zapisywania tablic. Przyjmuje adres docelowy i tablicę.
Jeżeli mamy do zapisania wiele obiektów, do których dostęp mamy tylko za pomocą wskaźnika to używamy pierwszej wersji.

Read ma cztery wersje. Pierwsza - podstawowa, przyjmuje adres źródłowy, adres do bufora i jego wielkość.
Druga wersja służy do odczytania jednego obiektu i zwraca go (może zostać skopiowany, jeżeli nie zadziała return value optimization).
Trzecia wersja również służy do odczytania jednego obiektu, ale zwraca inteligentny wskaźnik.
Czwarta wersja odczytuje wiele obiektów (pobiera ich ilość) i również zwraca do nich inteligentny wskaźnik.

Zastosowanie w praktyce:

Kopiuj
#include "ProcessMemory.hpp"

#include <memory>
#include <string>

#include <Windows.h>
#include <assert.h>

struct Test
{
	char Values[16];

	Test()
	{
		for(int i = 0; i < 16; i++)
			Values[i] = rand() % 256;
	}

	bool IsEqualTo(const Test& another)
	{
		for(int i = 0; i < 16; i++)
		{
			if(Values[i] != another.Values[i])
				return false;
		}

		return true;
	}
};

int main()
{
	ProcessMemory processMemory(GetCurrentProcessId());

	{
		double original = 3.14;
		double retrieved = processMemory.Read<double>(&original);

		assert(original == retrieved);
	}

	{
		Test original;
		std::unique_ptr<Test> retrieved = processMemory.Read<Test*>(&original);

		assert(retrieved->IsEqualTo(original));
	}

	{
		Test originals[5];
		std::unique_ptr<Test[]> retrieved = processMemory.Read<Test[]>(originals, 5);

		for(int i = 0; i < 5; i++)
			assert(retrieved[i].IsEqualTo(originals[i]));
	}

	{
		double original = 3.14;
		double placeholder;
		
		processMemory.Write(&placeholder, original);

		assert(original == placeholder);
	}

	{
		Test originals[5];
		auto placeholder = std::unique_ptr<Test[]>(new Test[5]);

		processMemory.Write(placeholder.get(), originals);

		for(int i = 0; i < 5; i++)
			assert(placeholder[i].IsEqualTo(originals[i]));
	}

	{
		const char* original = "testowy napis";

		std::unique_ptr<char[]> retrieved = processMemory.Read<char[]>(original, strlen(original) + 1);

		assert(strcmp(original, retrieved.get()) == 0);
	}

	{
		std::string original = "testowy napis";
		std::string retreived = processMemory.Read<char[]>(&original[0], original.size() + 1).get();

		assert(original == retreived);
	}

	return 0;
}

I sama klasa (powinna być leak-free, ale nie testowałem):

Kopiuj
#pragma once

#include <Windows.h>

#include <memory>
#include <exception>

#include <boost\type_traits\is_pointer.hpp>
#include <boost\type_traits\is_array.hpp>
#include <boost\type_traits\remove_pointer.hpp>
#include <boost\type_traits\remove_bounds.hpp>
#include <boost\utility\enable_if.hpp>

class ProcessMemory
{
private:
	HANDLE _processHandle;

	bool IsValidHandle(HANDLE handle)
	{
		return handle != NULL && handle != INVALID_HANDLE_VALUE;
	}

public:
	ProcessMemory(int processId)
	{
		_processHandle = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, false, processId);

		if(!IsValidHandle(_processHandle)) throw std::exception();
	}

	~ProcessMemory()
	{
		if(IsValidHandle(_processHandle))
		{
			CloseHandle(_processHandle);
			_processHandle = NULL;
		}
	}

	void Read(LPCVOID address, LPVOID buffer, SIZE_T size)
	{
		SIZE_T bytesRead;

		if(ReadProcessMemory(_processHandle, address, buffer, size, &bytesRead) == 0)
			throw std::exception();

		if(bytesRead != size)
			throw std::exception();
	}

	template<typename T>
	T Read(LPCVOID address, ...)
	{
		T object;

		Read(address, &object, sizeof(T));

		return object;
	}

	template<typename T>
	std::unique_ptr<typename boost::remove_pointer<T>::type>
	Read(LPCVOID address, typename boost::enable_if<boost::is_pointer<T>>::type* dummy = 0)
	{
		typedef boost::remove_pointer<T>::type TType;

		TType* object = new TType;
		
		try
		{
			Read(address, object, sizeof(TType));
		}
		catch(...)
		{
			delete object;

			throw;
		}

		return std::unique_ptr<TType>(object);
	}

	template<typename T>
	std::unique_ptr<T> Read(LPCVOID address, size_t elementCount, typename boost::enable_if<boost::is_array<T>>::type* dummy = 0)
	{
		typedef boost::remove_bounds<T>::type TType;

		TType* objects = new TType[elementCount];
		
		try
		{
			Read(address, objects, sizeof(TType) * elementCount);
		}
		catch(...)
		{
			delete[] objects;

			throw;
		}

		return std::unique_ptr<TType[]>(objects);
	}

	void Write(LPVOID address, LPCVOID buffer, SIZE_T size)
	{
		SIZE_T bytesWritten;

		if(WriteProcessMemory(_processHandle, address, buffer, size, &bytesWritten) == 0)
			throw new std::exception;

		if(bytesWritten != size)
			throw std::exception();
	}

	template<typename T>
	void Write(LPVOID address, const T &object)
	{
		Write(address, &object, sizeof(T));
	}

	template<typename T, size_t elementCount>
	void Write(LPVOID address, T (&objects)[elementCount])
	{
		Write(address, &objects, sizeof(objects));
	}
};
edytowany 3x, ostatnio: Rev
TheAifam5
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 6 lat
  • Postów:127
0

Bardzo Ci dziękuję! :)
Mógłby ktoś mi wytłumaczyć działanie smart pointerów..? Bardzo chciałbym sie ich nauczyć.. :) Jakieś przykłady byłyby mile widziane ;)


Wole programowac niz spac :)
matek3005
  • Rejestracja:prawie 15 lat
  • Ostatnio:prawie 5 lat
  • Postów:358
0
aifam96 napisał(a):

Mógłby ktoś mi wytłumaczyć działanie smart pointerów..? Bardzo chciałbym sie ich nauczyć.. :) Jakieś przykłady byłyby mile widziane ;)

tutaj masz przykładowy rozdział z heliona. Poza tym fraza "inteligenty wskaźnik" w znanej wyszukiwarce powinna zwrócić satysfakcjonujące wyniki.

TheAifam5
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 6 lat
  • Postów:127
0

Dziękuję ;) Wgl dziękuję za każdą odpowiedź.. bo każda odp mi pomaga ;) Fajnie forum :D


Wole programowac niz spac :)
edytowany 1x, ostatnio: TheAifam5
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
2

@Rev: masz doświadczenie z językami Java lub C#?

IMHO w linijce tego typu masz dwa błędy:

Kopiuj
throw new std::exception;
  1. wywołujesz throw z "new" zamiast z obiektem jak inni
  2. zgłaszasz wyjątek bez podania przyczyny

Lepsze byłoby:

Kopiuj
throw std::runtime_error ("ProcessMemory.Write failed");

Ad. 1)
Jak obsłużysz wyjątek zgłoszony z "new"? Chyba inaczej niż normalnie. A jeśli inaczej to znaczy że albo swoje wyjątki obsługujesz zawsze inaczej niż standardowe, albo masz rozjazd w kodzie...

Poniżej przykład:
http://ideone.com/lO493

edytowany 3x, ostatnio: vpiotr
RE
Moderator
  • Rejestracja:około 18 lat
  • Ostatnio:12 miesięcy
0

Oczywiście, preferowany sposób rzucania wyjątków w C++ jest poprzez zwykłe stworzenie obiektu i łapanie przez stałą referencję. Wtedy nie trzeba martwić się o pamięć po nim. Mój główny język to C# i tak z rozpędu rzuciłem je przez new ;). Raczej chodziło mi o pokazanie "niecieknącego" RAII niż faktyczne raportowanie błędów. A z tego co kojarzę to ludzie radzą też, żeby nie polegać na domyślnym tekście z runtime_error i what z exception.

vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
0
Rev napisał(a):

A z tego co kojarzę to ludzie radzą też, żeby nie polegać na domyślnym tekście z runtime_error i what z exception.

Podaj powody bo brzmi trochę jak plotka zasłyszana u cioci na imieninach.

http://www.cplusplus.com/reference/std/stdexcept/runtime_error/

TheAifam5
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 6 lat
  • Postów:127
0

A jeszcze jedno pytanie... Smart pointery powoli rozumiem. ;) Dzięki, fajna żecz ;) A tak jeszcze jedno ;)

  1. Chciałbym zrobić system wyjątków, może być try...catch? czy lepiej jakiś inny użyć..?

  2. A i może mi ktoś wyjaśnić czemu w template jest czasem <class T> albo <typename T>? Jest jakaś różnica?

  3. Jak sprawdzić typy w template (w IF)... np:

Kopiuj
template <class T> bool Sprawdz(T typ)
{
if (T == char) // CHODZI DOKŁADNIE TUTAJ, JEST JAKIŚ SPOSÓB NA TO?
{
std::cout << "Typ: CHAR" << std::endl;
}
else
{
std::cout << "Typ: INNY" << std::endl;
}
}
  1. Jest takie coś (Z powyższego kodu Rev):
Kopiuj
        if(bytesWritten != size)
                throw new std::exception;

Jak to: "throw new std::exception;" zamienić na boosta?


Wole programowac niz spac :)
edytowany 3x, ostatnio: TheAifam5
byku_guzio
  • Rejestracja:prawie 15 lat
  • Ostatnio:około 7 lat
0
  1. może być try...catch, a nawet musi jak rozmawiamy o wyjątkach
  2. Nie ma różnicy, tu jest opisane dlaczego są dwa keywordy: http://blogs.msdn.com/b/slippman/archive/2004/08/11/212768.aspx
  3. operator typeid: if(typeid(T) == typeid(char)) ... (nie sprawdzałem, ale powinno działać)
  4. co znaczy zamienić na boost'a?

CN
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 9 lat
  • Postów:38
0
  1. to jest jakiś inny?
  2. podałem ci rozwiązanie już wcześniej
  3. a po co cokolwiek zamieniać?

//@byku_guzio był szybszy

edytowany 2x, ostatnio: cnyk
adf88
  • Rejestracja:ponad 21 lat
  • Ostatnio:prawie 12 lat
0
  1. A jest jakiś inny?
  2. Wszystko jedno, kwestia umowna
  3. Użyj mechanizmu "explicit template specialization" - możesz zdefiniować osobno funkcję/klasę dla danego typu a osobno dla typu nieznanego:
Kopiuj
template <class T> bool Sprawdz() {
    std::cout << "Typ: INNY" << std::endl;
}

template <> bool Sprawdz<char>()
{
    std::cout << "Typ: CHAR" << std::endl;
}
  1. Po prostu zamiast std::exception użyj innego typu.
adf88
Ale się rzucili do odpowiedzi :)
byku_guzio
hehe, pewnie dlatego, że to nie kolejny temat z serii jak z form1 dobrać się do form2 :p BTW. fajny pomysł z tym 3, lepiej niż korzystanie z RTTI
TheAifam5
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 6 lat
  • Postów:127
0

Dzięki ;)
Mam jeszcze pytania :D Jak na razie jedno ;P

Mam w main.cpp "try... catch".. w "catch" jest MessageBox wyświetlający co poszło nie tak.. Niestety nie wyświetla mi tego MessageBox-a tylko przechodzi do debuggera... Wiecie jak to naprawić? ;)

Zamiast "std::exception" użyłem "throw new boost::exception_ptr();". Dobrze zrobiłem?


Wole programowac niz spac :)
edytowany 1x, ostatnio: TheAifam5
byku_guzio
  • Rejestracja:prawie 15 lat
  • Ostatnio:około 7 lat
0

Pewnie źle łapiesz wyjątek.

"Zamiast ..." - nie, exception_ptr to jest wskaźnik http://www.boost.org/doc/libs/1_41_0/libs/exception/doc/exception_ptr.html Może na razie zostaw boosta i ogarnij porządnie wyjątki :)


TheAifam5
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 6 lat
  • Postów:127
0

Dobrze.. zostanę przy std::exception ;)

Mam kod (by Rev , po edycji :D):

Kopiuj
template<class T> bool Read(unsigned int Address, const T* Buffer)
		{
			SIZE_T bytesRead;
			SIZE_T size = sizeof(T);

			if(typeid(T) == typeid(char))
				size = strlen(*Buffer) + 1;
 
			if(ReadProcessMemory(_processHandle, (LPCVOID)Address, (LPVOID)Buffer, size, &bytesRead) == 0)
                throw new std::exception;
 
			if(bytesRead != size)
                throw new std::exception;
		}

"bool Read(unsigned int Address, const T* Buffer)" użyć "T&" czy zostawić? Chodzi mi o wygode :D

A to mój main.cpp:

Kopiuj
// TiBot.cpp: Określa punkt wejścia dla aplikacji konsoli.
//

#include "stdafx.h"
#include "ProcessMemory.h"

/* Moje notatki:
Mając wskaźnik & możemy bezpośrednio odczytać z niego wartość.
Mając wskaźnik * musimy podać mu adres i wtedy można odczytać z niego wartość przed zmienną dodawając *.

	int i = 0;
	int* x = &i;
	int& z = i;
	int& y = *x;
	int* w = &y;

	std::cout << i << std::endl; // Wartość
	std::cout << *x << std::endl; // Wartość
	std::cout << z << std::endl; // Wartość
	std::cout << y << std::endl; // Wartość
	std::cout << *w << std::endl; // Wartość

	std::cout << &i << std::endl; // Adres
	std::cout << x << std::endl; // Adres
	std::cout << &z << std::endl; // Adres
	std::cout << &y << std::endl; // Adres
	std::cout << w << std::endl; // Adres
*/

int main(int argc, char* argv[])
{
	try
	{
		boost::scoped_ptr<ProcessMemory> pm (new ProcessMemory("TibiaClient"));
		char string;	
		pm->Read(0x0064004C, &string);
		std::cout << string << std::endl;
	}
	catch(std::exception& ex)
	{
		MessageBox(NULL, ex.what(), "TEST", 0);
	}
	system("pause");
	return 0;
}

Odczytuje mi tylko jeden wyraz... Wiem że w template:

Kopiuj
			SIZE_T size = sizeof(T);

			if(typeid(T) == typeid(char))
				size = strlen(*Buffer) + 1;

To jest niepoprawne ale po wstawieniu w size=128 też odczytuje jeden wyraz i na końcu błąd.. Jak naprawić? :)


Wole programowac niz spac :)
edytowany 2x, ostatnio: TheAifam5
adf88
  • Rejestracja:ponad 21 lat
  • Ostatnio:prawie 12 lat
0
  1. Dlaczego const skoro zmieniasz tą pamięć?!?!?!?!?!
  2. Czy użyjesz referencji czy wskaźnika to w zasadzie kwestia umowna. Podoba mi się konwencja używania wyłącznie wskaźników gdy przekazujemy coś nie-const. Wtedy jak widzimy kod wywołujący funkcję i w nim operator &:
Kopiuj
foo(&x);

to od razu widać, że zmienna x może być zmieniona przez funkcję foo.
3. Ta funkcja miała odczytać wartość pojedynczej zmiennej. Dlaczego czytając jeden znak char ty chcesz czytać dwa znaki? I dlaczego strlen? Chyba nie wiesz jak strlen działa, tą funkcją nie sprawdzisz rozmiaru tablicy. Kompletnie pomieszałeś wszystko. Jeśli chcesz odczytać łańcuch znaków aż do natrafienia na bajt zerowy to zrób osobną funkcję ReadString. A Read pozostaw w spokoju, niech służy do odczytania zmiennej/tablicy zmiennych.

TibiaClient
no i wszystko jasne ;)

edytowany 8x, ostatnio: adf88
TheAifam5
Heh. robie to do zabawy... ;) Nie mam złych zamiarów.. :D Idę do technikum (1kl) informatycznego i mam do wyboru 2 języki Delphi i C++, a c++ bardziej do mnie przemawia :) A wiadomo że Tibia to MMORPG czyli jak zedytuje pamięć i tak po relogu nie będzie cały czas tej samej tylko taka jaką ma serwer... :D
adf88
Nie potępiam, wręcz przeciwnie. Niestety wpasowujesz się w pewien stereotyp... było tu kilka takich od Tibii. Ale nie martw się, nie należysz do nich.
TheAifam5
Heh. dzięki.. :) A tak ogólnie.. jak na 16 latka, dobrze mi idzie programowanie? ;) Uczę się wszytkiego po trochu.. Siedzę od 10 do 3 w nocy i pisze ;) Delphi, PHP, LUA, C++ .. ogólnie chce pooznać wszystkie języki.... :D
adf88
Jak ci idzie? No chyba dobrze, ciężko ocenić. Poziom umiejętności nie jest istotny. Ważne, że się rozwijasz, dociekasz problemu, starasz zrozumieć i zakodzić coś samemu ... tak trzymać!
TheAifam5
Jestem samoukiem ;) Czasem potrzebuje pomocy od innych np: od Was ;) Gdy nie miałem internetu sam wszystko robiłem :D Warto sobie jednak czasem popytać i dowiedzieć się.. Jak każdy, uczę się na błędach :)
TheAifam5
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 6 lat
  • Postów:127
0

Kod aktualnie tak wygląda:
main.cpp:

Kopiuj
// TiBot.cpp: Określa punkt wejścia dla aplikacji konsoli.
//

#include "stdafx.h"
#include "ProcessMemory.h"

/*
Mając referencje & możemy bezpośrednio odczytać z niego wartość.
Mając wskaźnik * musimy podać mu adres i wtedy można odczytać z niego wartość przed zmienną dodawając *.

	int i = 0;
	int* x = &i;
	int& z = i;
	int& y = *x;
	int* w = &y;

	std::cout << i << std::endl; // Wartość
	std::cout << *x << std::endl; // Wartość
	std::cout << z << std::endl; // Wartość
	std::cout << y << std::endl; // Wartość
	std::cout << *w << std::endl; // Wartość

	std::cout << &i << std::endl; // Adres
	std::cout << x << std::endl; // Adres
	std::cout << &z << std::endl; // Adres
	std::cout << &y << std::endl; // Adres
	std::cout << w << std::endl; // Adres
*/

int main(int argc, char* argv[])
{
	try
	{
		boost::scoped_ptr<ProcessMemory> pm (new ProcessMemory("TibiaClient"));
		char string[256];	
		pm->Read(0x0064004C, string);
		std::cout << string << std::endl;
		pm->Write(0x0064004C, "MateuszX");
	}
	catch(std::exception& ex)
	{
		MessageBox(NULL, ex.what(), "TEST", 0);
	}
	system("pause");
	return 0;
}

ProcessMemory.h:

Kopiuj
#pragma once
 
class ProcessMemory
{
private:
        HANDLE _processHandle;
 
        bool IsValidHandle(HANDLE handle);
 
public:
        ProcessMemory(const char* ClassName);
 
        ~ProcessMemory();

		template<class T> bool Read(unsigned int Address, T& Buffer)
		{
			SIZE_T bytesRead;
			SIZE_T size = sizeof(Buffer);
 
			if(ReadProcessMemory(_processHandle, (LPCVOID)Address, (LPVOID)&Buffer, size, &bytesRead) == 0)
                throw std::runtime_error ("ProcessMemory.ReadMemoryProcess failed");
 
			if(bytesRead != size)
                throw std::runtime_error ("ProcessMemory.Read.bytes!=size failed");

			return true;
		}

		template<class T> bool Write(unsigned int Address, const T& Buffer)
		{
			SIZE_T bytesWritten;
			SIZE_T size = sizeof(T);

			if(WriteProcessMemory(_processHandle, (LPVOID)Address, (LPCVOID)&Buffer, size, &bytesWritten) == 0)
                throw std::runtime_error ("ProcessMemory.WriteMemoryProcess failed");
 
			if(bytesWritten != size)
                throw std::runtime_error ("ProcessMemory.Write.bytes!=size failed");

			return true;
		}

		template<> bool Write<char>(unsigned int Address, const char& Buffer)
		{
			SIZE_T bytesWritten;
			SIZE_T size = strlen(&Buffer) + 1;

			if(WriteProcessMemory(_processHandle, (LPVOID)Address, (LPCVOID)&Buffer, size, &bytesWritten) == 0)
                throw std::runtime_error ("ProcessMemory.WriteMemoryProcess failed - CHAR");
 
			if(bytesWritten != size)
                throw std::runtime_error ("ProcessMemory.Write.bytes!=size failed - CHAR");

			return true;
		}
};

Może ktoś przeanalizować to? Tzn czy nie ma błędów.. Oczywiście wszytko działa... a jeśli kod będzie dobry na pewno komuś się przyda ;)


Wole programowac niz spac :)
TheAifam5
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 6 lat
  • Postów:127
0

Proooosszzze :D


Wole programowac niz spac :)
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
0
  • main wygląda dziwnie: cout + MessageBox - albo konsola albo okienko
  • bool Write(), bool Read() - deklaracja myląca, skoro w przypadku błędu wywalasz exception, lepiej będzie void Write(), void Read()
  • specjalizacja dla char powinna operować na pojedynczym znaku (nagłówek) lub na tablicy znaków (strlen). Musisz się zdecydować co chcesz osiągnąć. jeśli to drugie to raczej chodzi o specjalizację
Kopiuj
< char *>
  • nazwa parametru Address jest myląca. W rzeczywistości chodzi o offset. Address nie może być typu unsigned int, offset - tak.
  • zrób test z prawdziwego zdarzenia - czytaj dane procesu w którym się znajdujesz, które jesteś pewien że istnieją - jak w przykładzie u Rev-a
  • Twoje wersje Read i Write nie działają z klasami, dlatego na wzór kodu Rev-a mógłbyś zastosować boost::is_pod podobnie jak on zrobił is_array, ale nie pytaj mnie jak - sam musiałbym to potestować. Dzięki temu Twój kod nie będzie mógł być uruchomiony z obiektem jako parametrem - i dobrze
edytowany 3x, ostatnio: vpiotr
TheAifam5
Dzięki.. ;) Będę kombinował ;)
TheAifam5
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 6 lat
  • Postów:127
0

Witam, przepraszam że odświeżam lecz potrzebuje tą samą klasę (Rev-a) pod Linuxa..


Wole programowac niz spac :)
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)