Related
Summarize The Problem
I'm building an operating system using C++ on Linux Mint in Parallels Desktop Mac.
I just added keyboard support except there was a problem...
When I press one key on the keyboard, it will create around 5 or more characters. This is an image of the problem:
Describe What you've tried
All of the sources were talking about Linux kernel so I couldn't find anything. I didn't try anything.
Show some code
print.h
#ifndef PRINT_H
#define PRINT_H
#include "types.h"
#include "colours.h"
class print {
public:
void printf(char *str);
void printf(int num);
void itoa(int num, char *number);
uint32_t digit_count(int num);
uint32_t strlen(const char *str);
void print_char(char ch);
void newLine();
void init_vga(uint8_t fore_color, uint8_t back_color);
void clear_vga_buffer(uint16_t **buffer, uint8_t fore_color, uint8_t back_color);
uint16_t vga_entry(unsigned char ch, uint8_t fore_color, uint8_t back_color);
void setTextColors(uint8_t foreColor, uint8_t back_color);
print *getPrinter();
void setPrinter(print *printer1);
private:
print *ksafdkjlasdlfk;
//index for video buffer array
uint32_t vga_index;
//counter to store new lines
uint32_t next_line_index = 1;
//fore & back color values
uint8_t g_fore_color = WHITE, g_back_color = BLUE;
//digit ascii code for printing integers
int digit_ascii_codes[10] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
#define VGA_ADDRESS 0xB8000
#define BUFSIZE 2200
uint16_t *vga_buffer;
#define NULL 0
};
#endif
print.cpp
#include "print.h"
void print::printf(char *str) {
uint32_t index = 0;
while (str[index]) {
print_char(str[index]);
index++;
}
}
void print::printf(int num) {
char str_num[digit_count(num) + 1];
itoa(num, str_num);
printf(str_num);
}
void print::itoa(int num, char *number) {
int dgcount = digit_count(num);
int index = dgcount - 1;
char x;
if (num == 0 && dgcount == 1) {
number[0] = '0';
number[1] = '\0';
} else {
while (num != 0) {
x = num % 10;
number[index] = x + '0';
index--;
num = num / 10;
}
number[dgcount] = '\0';
}
}
uint32_t print::digit_count(int num) {
uint32_t count = 0;
if (num == 0)
return 1;
while (num > 0) {
count++;
num = num / 10;
}
return count;
}
uint32_t print::strlen(const char *str) {
uint32_t length = 0;
while (str[length])
length++;
return length;
}
void print::print_char(char ch) {
vga_buffer[vga_index] = vga_entry(ch, g_fore_color, g_back_color);
vga_index++;
}
void print::newLine() {
if (next_line_index >= 55) {
next_line_index = 0;
clear_vga_buffer(&vga_buffer, g_fore_color, g_back_color);
}
vga_index = 80 * next_line_index;
next_line_index++;
}
void print::init_vga(uint8_t fore_color, uint8_t back_color) {
vga_buffer = (uint16_t *) VGA_ADDRESS;
clear_vga_buffer(&vga_buffer, fore_color, back_color);
g_fore_color = fore_color;
g_back_color = back_color;
}
void print::clear_vga_buffer(uint16_t **buffer, uint8_t fore_color, uint8_t back_color) {
uint32_t i;
for (i = 0; i < BUFSIZE; i++) {
(*buffer)[i] = vga_entry(NULL, fore_color, back_color);
}
next_line_index = 1;
vga_index = 0;
}
uint16_t print::vga_entry(unsigned char ch, uint8_t fore_color, uint8_t back_color) {
uint16_t ax = 0;
uint8_t ah = 0, al = 0;
ah = back_color;
ah <<= 4;
ah |= fore_color;
ax = ah;
ax <<= 8;
al = ch;
ax |= al;
return ax;
}
void print::setTextColors(uint8_t foreColor, uint8_t back_color) {
g_fore_color = foreColor;
g_back_color = back_color;
}
print *print::getPrinter() {
return ksafdkjlasdlfk;
}
void print::setPrinter(print *printer1) {
ksafdkjlasdlfk = printer1;
}
keyboard.h
#ifndef APOS_KEYBOARD_H
#define APOS_KEYBOARD_H
#include "../../utils/types.h"
#include "../../utils/print.h"
#include "char.h"
class keyboard {
public:
void enableKeyboard();
void test_input();
void sleep(uint32_t timer_count);
void wait_for_io(uint32_t timer_count);
char get_input_keycode();
void outb(uint16_t port, uint8_t data);
uint8_t inb(uint16_t port);
};
#endif //APOS_KEYBOARD_H
keyboard.cpp
#include "keyboard.h"
uint8_t keyboard::inb(uint16_t port) {
uint8_t ret;
asm volatile("inb %1, %0" : "=a"(ret) : "d"(port));
return ret;
}
void keyboard::outb(uint16_t port, uint8_t data) {
asm volatile("outb %0, %1" : "=a"(data) : "d"(port));
}
char keyboard::get_input_keycode() {
char ch = 0;
while ((ch = inb(KEYBOARD_PORT)) != 0) {
if (ch > 0)
return ch;
}
return ch;
}
/*
keep the cpu busy for doing nothing(nop)
so that io port will not be processed by cpu
here timer can also be used, but lets do this in looping counter
*/
void keyboard::wait_for_io(uint32_t timer_count) {
while (1) {
asm volatile("nop");
timer_count--;
if (timer_count <= 0)
break;
}
}
void keyboard::sleep(uint32_t timer_count) {
wait_for_io(timer_count);
}
void keyboard::test_input() {
char ch = 0;
char keycode = 0;
do {
keycode = get_input_keycode();
if (keycode == KEY_ENTER) {
print printt;
printt.getPrinter()->newLine();
} else {
ch = get_ascii_char(keycode);
print printt;
printt.getPrinter()->print_char(ch);
}
sleep(0x02FFFFFF);
} while (ch > 0);
}
void keyboard::enableKeyboard() {
test_input();
}
The kernel.cpp just has the test_intput command and prints a few things.
There are a few files there, but that main ones are the kernel.cpp, hardware/keyboard/all the files there.
Either use a seperate Thread to handle the input reckognition function, that way you can use a sleep without blocking the main Thread. You could also save the current pressed key and save it as a previous key and check if it has changed, if not the button has not been released yet. so you can avoid multiples.
I am using a third party WinAPI-based Serial library (SerialPort) in a C++ program to command a LED strip (iLED and pixel color), but it turns out it only seems to work for one command - if I send the same command a second time, the color of that pixel takes another random colour and for some reason the first LED turns on too with a random colour.
Here is a link to a video of what happens when the simplified code below is run, i.e. when pixel 3, 5 and 7 are commanded over and over to be red, green, and blue respectively.
https://drive.google.com/file/d/1RRAshnhPz96YGJtmETy3vuGi25QjxqJz/view?usp=drivesdk
I suspected the Serial.read() weren't synchronised so I added a start byte but it didn't seem to work either, that's what the code below does.
What is happening ?
SerialPort.h (source: https://blog.manash.me/serial-communication-with-an-arduino-using-c-on-windows-d08710186498)
#ifndef SERIALPORT_H
#define SERIALPORT_H
#define ARDUINO_WAIT_TIME 2000
#define MAX_DATA_LENGTH 255
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
class SerialPort
{
private:
HANDLE handler;
bool connected;
COMSTAT status;
DWORD errors;
public:
SerialPort(char const *portName, unsigned long baudrate);
~SerialPort();
int readSerialPort(char *buffer, unsigned int buf_size);
bool writeSerialPort(char *buffer, unsigned int buf_size);
bool isConnected();
};
#endif // SERIALPORT_H
SerialPort.cpp (source: https://blog.manash.me/serial-communication-with-an-arduino-using-c-on-windows-d08710186498)
#include "serialport.h"
SerialPort::SerialPort(char const *portName, unsigned long baudrate)
{
this->connected = false;
this->handler = CreateFileA(static_cast<LPCSTR>(portName),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (this->handler == INVALID_HANDLE_VALUE){
if (GetLastError() == ERROR_FILE_NOT_FOUND){
printf("ERROR: Handle was not attached. Reason: %s not available\n", portName);
}
else
{
printf("ERROR!!!");
}
}
else {
DCB dcbSerialParameters = {0};
if (!GetCommState(this->handler, &dcbSerialParameters)) {
printf("failed to get current serial parameters");
}
else {
dcbSerialParameters.BaudRate = baudrate;
dcbSerialParameters.ByteSize = 8;
dcbSerialParameters.StopBits = ONESTOPBIT;
dcbSerialParameters.Parity = NOPARITY;
dcbSerialParameters.fDtrControl = DTR_CONTROL_ENABLE;
if (!SetCommState(handler, &dcbSerialParameters))
{
printf("ALERT: could not set Serial port parameters\n");
}
else {
this->connected = true;
PurgeComm(this->handler, PURGE_RXCLEAR | PURGE_TXCLEAR);
Sleep(ARDUINO_WAIT_TIME);
}
}
}
}
SerialPort::~SerialPort()
{
if (this->connected){
this->connected = false;
CloseHandle(this->handler);
}
}
int SerialPort::readSerialPort(char *buffer, unsigned int buf_size)
{
DWORD bytesRead;
unsigned int toRead;
ClearCommError(this->handler, &this->errors, &this->status);
if (this->status.cbInQue > 0){
if (this->status.cbInQue > buf_size){
toRead = buf_size;
}
else toRead = this->status.cbInQue;
}
if (ReadFile(this->handler, buffer, toRead, &bytesRead, NULL)) return bytesRead;
return 0;
}
bool SerialPort::writeSerialPort(char *buffer, unsigned int buf_size)
{
DWORD bytesSend;
if (!WriteFile(this->handler, (void*) buffer, buf_size, &bytesSend, 0)){
ClearCommError(this->handler, &this->errors, &this->status);
return false;
}
else return true;
}
bool SerialPort::isConnected()
{
return this->connected;
}
main.cpp
#include <iostream>
#include "serialport.h"
using namespace std;
int main()
{
SerialPort serial("COM3", 115200);
while(1) {
unsigned char buffer[] = {255,3, 254, 0, 0};
serial.writeSerialPort((char*)buffer, 4);
unsigned char buffer2[] = {255,5, 0, 254, 0};
serial.writeSerialPort((char*)buffer2, 4);
unsigned char buffer3[] = {255,7, 0, 0, 254};
serial.writeSerialPort((char*)buffer3, 4);
}
return 0;
}
Arduino firmware
#include <FastLED.h>
#define BAUDRATE 115200
#define N_BYTES_MSG 4
#define N_LEDS 120
#define DATA_PIN 6
CRGB leds[N_LEDS] = {0};
void setup() {
FastLED.addLeds<WS2811, DATA_PIN, BRG>(leds, N_LEDS); //I don't know why the colours are BRG on this strip
FastLED.show();
Serial.begin(BAUDRATE);
}
void loop() {
//Check for a quadruplet of bytes (iLED R G B) led by start byte
if(Serial.available() >= N_BYTES_MSG+1 && Serial.read() == 255) {
//Read message
unsigned char buf[N_BYTES_MSG] = {0};
for(unsigned char i=0; i < N_BYTES_MSG; i++) {
buf[i] = Serial.read();
}
if(buf[0] < N_LEDS) { //Valid ID
leds[buf[0]] = CRGB(buf[1],buf[2],buf[3]); //Update LED state in internal representation
FastLED.show(); //Refresh LEDs based on internal representation
}
}
}
Note that the LED strip seems to work properly on its own, since I successfully tested moving at constant speed a single pixel.
The LED strip itself is the easiest debug route I have since I didn't manage to make readSerialPort() work yet and the COM port is hogged by the program so I can't get a handle on it (can we sniff that somehow?).
I test serial.writeSerialPort on Windows 10 desktop with Arduino Uno. It works for me.
The following is the code I used:
On windows:
#include <iostream>
#include "serialport.h"
using namespace std;
int main()
{
SerialPort serial("COM4", 115200);
while (1) {
unsigned char buffer[] = { 255,3, 254, 0, 0 };
serial.writeSerialPort((char*)buffer, 5);
unsigned char buffer2[] = { 255,5, 0, 254, 0 };
serial.writeSerialPort((char*)buffer2, 5);
unsigned char buffer3[] = { 255,7, 0, 0, 254 };
serial.writeSerialPort((char*)buffer3, 5);
}
return 0;
}
On Arduino:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
#define BAUDRATE 115200
#define N_BYTES_MSG 4
#define N_LEDS 120
#define DATA_PIN 6
void setup() {
Serial.begin(BAUDRATE);
mySerial.begin(BAUDRATE);
mySerial.println("Start reading.");
delay(5000);
}
void loop() {
//Check for a quadruplet of bytes (iLED R G B) led by start byte
if(Serial.available() >= N_BYTES_MSG+1 && Serial.read() == 255) {
//Read message
unsigned char buf[N_BYTES_MSG] = {0};
for(unsigned char i=0; i < N_BYTES_MSG; i++) {
buf[i] = Serial.read();
}
for(unsigned char i=0; i < N_BYTES_MSG; i++) {
mySerial.print(buf[i]);
mySerial.print(",");
}
mySerial.print("\r\n");
//Serial.write("Read complete!");
}
}
I print the received data on Arduino:
I notice that the printed data messed up when the Windows sends fast as you did in the while(1) without delay. So try adding a delay between two writes to see if it works.
Add also note the problem as #paddy pointed out.
I didn't manage to make readSerialPort() work yet
Set unsigned int toRead = buf_size; in SerialPort.cpp works for me. Use the following code to read:
unsigned char readBuffer[20] = {};
serial.readSerialPort((char*)readBuffer, 20);
printf((char*)readBuffer);
printf("\n");
Read from Arduino result:
I am trying to monitor the assembly instructions of a functions opcode. I get the functions size in bytes by subtracting a stub address from the functions in memory. I am currently only looking for the mov instruction. When I display the currentByte, it outputs only Ú, which has a hex value of 0xDA, which is FIADD in assembly http://ref.x86asm.net/coder32.html#xDA Why does no mov instruction display?
#include <iostream>
#include <Windows.h>
#include <ctime>
#include <vector>
#define PUSH 0x50
#define POP 0x58
#define MOV 0xB8
#define NOP 0x90
#define ADD 0x01
#define AND 0x21
#define XOR 0x31
#define OR 0x09
#define SBB 0x19
#define SUB 0x29
using namespace std;
int add(int x, int y)
{
int result;
__asm
{
mov eax, x
add eax, y
mov result, eax
xor eax, eax
}
return result;
}
void stub() { return; }
DWORD GetFunctionSize(DWORD* functionStartAddress, DWORD* stub)
{
DWORD dwOldProtect;
DWORD *func, *stubAddr;
func = (DWORD*)functionStartAddress;
stubAddr = (DWORD*)stub;
DWORD size = func - stubAddr;
VirtualProtect(func, size, PAGE_EXECUTE_READWRITE, &dwOldProtect);
return size;
}
void GetCurrentByte(PVOID function)
{
vector<PBYTE> currByte;
PBYTE pCurrentByte = (PBYTE)function;
if (*pCurrentByte == MOV)
{
cout << "MOV instr.\n";
}
cout << *pCurrentByte;
currByte.push_back(pCurrentByte);
}
int main()
{
DWORD size = GetFunctionSize((DWORD*)&add, (DWORD*)&stub);
for (int i = 0; i < size; i++)
{
GetCurrentByte(add);
}
system("pause");
return 0;
}
Why does no mov instruction display?
If you are in debugging mode, you need to know that you are passing a wrong address to the GetCurrentDate(PVOID), thats mean you are reading bytes from a wrong address and there is another few mistakes, to solve this issue follow those steps :
Firstly, the code bytes generated from :
mov eax, x // code bytes: 8B 45 08
mov result, eax // code bytes: 89 45 FC
0x8B and 0x89 are the values that you should look for inside your add(int, int) function.
secondly, to get the address of the first byte of your add(int, int) function i suggest to use this function :
#define ASM_CALL 0x000000E8
#define ASM_JMP 0x000000E9
#define ASM_CALL_SIZE 0x00000001
#define ASM_CALL_FULL_SIZE 0x00000005
DWORD GetFuncAddress(DWORD funcAddress)
{
BYTE calledAddress = *(BYTE*)funcAddress;
while (calledAddress == ASM_CALL || calledAddress == ASM_JMP) {
funcAddress = funcAddress + *(DWORD*)(funcAddress + ASM_CALL_SIZE) + ASM_CALL_FULL_SIZE;
calledAddress = *(BYTE*)funcAddress;
}
return funcAddress; // The address of the first byte of the function.
}
thirdly, i suggest an optimization inside your GetFunctionSize(DOWRD), as you know that your add function ends with a single return :
return result; // code bytes: C3
why not just loop throw the bytes of the add function, so when you find a byte equivalente to 0xC3, you will end up with the exact size of your function (in bytes), this code will make things clear:
#define ASM_RET 0xC3
SIZE_T GetFunctionSize(DWORD functionAddress)
{
SIZE_T funcSize = 0;
// Loop thru func's bytes, and breaks when return byte found.
while (*((PBYTE)functionAddress++) != RET)
funcSize++;
return funcSize;
}
fourthly, the GetCurrentByte(PVOID) function needs some maintenance, so i suggest :
#define ASM_MOV1 0x8B
#define ASM_MOV2 0x89
VOID GetCurrentByte(DWORD functionAddress, UINT &index)
{
BYTE tempByte = *((PBYTE)functionAddress + index);
// search for bytes which contains a mov instruction:
if (tempByte == ASM_MOV1 || tempByte == ASM_MOV2)
cout << "MOV instr found at : " << hex << ((DWORD)functionAddress + index) << endl;
}
finally, the full code will be like this :
#include <iostream>
#include <Windows.h>
#define ASM_RET 0xC3
#define ASM_MOV1 0x8B
#define ASM_MOV2 0x89
#define ASM_CALL 0xE8
#define ASM_JMP 0xE9
#define ASM_CALL_SIZE 0x01
#define ASM_CALL_FULL_SIZE 0x05
using namespace std;
INT add(INT x, INT y)
{
int result;
__asm
{
mov eax, x
add eax, y
mov result, eax
xor eax, eax
}
return result;
}
DWORD GetFuncAddress(DWORD funcAddress)
{
BYTE calledAddress = *(BYTE*)funcAddress;
while (calledAddress == ASM_CALL || calledAddress == ASM_JMP) {
funcAddress = funcAddress + *(DWORD*)(funcAddress + ASM_CALL_SIZE) + ASM_CALL_FULL_SIZE;
calledAddress = *(BYTE*)funcAddress;
}
return funcAddress;
}
SIZE_T GetFunctionSize(DWORD functionAddress)
{
SIZE_T funcSize = 0;
while (*((PBYTE)functionAddress++) != ASM_RET)
{
funcSize++;
}
return funcSize;
}
VOID GetCurrentByte(DWORD functionAddress, UINT &index)
{
BYTE tempByte = *((PBYTE)functionAddress + index);
if (tempByte == ASM_MOV1 || tempByte == ASM_MOV2)
cout << "MOV instr found at : " << hex << ((DWORD)functionAddress + index) << endl;
}
INT main()
{
DWORD funcAddress = GetFuncAddress((DWORD)add); // Get func address.
SIZE_T size = GetFunctionSize(funcAddress); // Get func size (bytes).
for (UINT i = 0; i < size; i++) // loop thru the function memory block.
{
GetCurrentByte(funcAddress, i);
}
system("pause");
return 0;
}
Don't be surprised if you found many MOV instructions in your function because the compiler created them.
Amrane Abdelkader.
GetCurrentByte() looks at the first byte every time you call it. Looking at the first byte size times doesn't help you.
I'm just beginning with directx/directinput development and I'm running some tests with some code samples I've found online. Anyway, I want to hook an application that uses dinput8 to send my own custom input to the forewindow and I'm working with this base to do it:
// dllmain.cpp : Defines the entry point for the DLL application.
#define _CRT_SECURE_NO_WARNINGS // ignore some warnings...
#define _CRT_NON_CONFORMING_SWPRINTFS // ...
#include "stdio.h"
#include <windows.h>
#include "detours.h"
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <time.h>
#include "dinput.h"
#pragma comment(lib, "detours.lib")
#pragma comment(lib, "user32.lib")
typedef HRESULT(__stdcall* GetDeviceState_t)(LPDIRECTINPUTDEVICE, DWORD, LPVOID *);
HRESULT __stdcall hkGetDeviceState(LPDIRECTINPUTDEVICE pDevice, DWORD cbData, LPVOID *lpvData);
DWORD Base = 0;
DWORD GetDeviceStateOffset = 0x7670; // This is the offset of GetDeviceState from DInput8.dll
// Open IDA and Import the DInput8.dll, then look in the Functions Table for DirectInput8Create
// There is an Address (1000XXXX or 0CXXXXX) - copy it and save it for later
// Then take a look for CDIDev_GetDeviceState and copy that address too
// Now substract the Address from CDIDev_GetDeviceState from DIrectInput8Create and u'll get your offset
HANDLE tmpHandle = NULL;
HMODULE hModDInput8 = NULL;
DWORD dwGetDeviceState = NULL;
FARPROC dwDirectInput8Create = NULL;
struct MyKeys
{
BYTE Key;
DWORD StartTime;
DWORD TTL;
BOOLEAN isDown;
};
MyKeys KeyBuffer[256];
DWORD WINAPI HookThread();
void add_log(char* format, ...);
void SendKeyDInput(byte DIK_, DWORD time);
GetDeviceState_t pGetDeviceState;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
add_log("==========LOG START==========");
add_log("DLL Attached");
add_log("Creating Thread...");
tmpHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&HookThread, 0, 0, 0);
if (!tmpHandle)
{
add_log("ThreadCreation Failed!");
}
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
DWORD WINAPI HookThread()
{
Base = (DWORD)GetModuleHandleA("test.exe");
add_log("Thread Created");
add_log("game.exe Base: %x", Base);
while (!hModDInput8)
{
add_log("Searching dinput8.dll...");
hModDInput8 = GetModuleHandle(L"dinput8.dll");
Sleep(100);
}
add_log("Found dinput8.dll: %x !", hModDInput8);
while (!dwDirectInput8Create)
{
add_log("Searching GetDeviceState...");
dwDirectInput8Create = GetProcAddress(hModDInput8, "DirectInput8Create");
Sleep(100);
}
add_log("Found DirectInput8Create: %x !", dwDirectInput8Create);
dwGetDeviceState = (DWORD)((DWORD)dwDirectInput8Create - GetDeviceStateOffset);
add_log("GetDevicestate is here (DirectInput8Create - %x): %x", GetDeviceStateOffset, dwGetDeviceState);
add_log("Hooking GetDeviceState...");
pGetDeviceState = (GetDeviceState_t)DetourAttach(&(PVOID&)dwGetDeviceState, (PBYTE)hkGetDeviceState);
add_log("Initiate Keyboard Buffer...");
//initiate buffer
for (int i = 0; i < 256; i++)
{
KeyBuffer[i].isDown = false;
KeyBuffer[i].Key = 0;
KeyBuffer[i].StartTime = 0;
KeyBuffer[i].TTL = 0;
}
add_log("Going into Main Loop...");
while (true)
{
if (GetAsyncKeyState(VK_F5) & 1 << 15)
{
// We check the Most Sigificant Bit from VK_F5 (F5) whilst we shifted it with 15 bits to left 1
// and then a small delay so we have enaught time to release the key
add_log("F5 pushed attempting to sendkey");
// Sleep a short time so we have time to release the F5 Key
Sleep(500);
// Now we send a A Key with 1 sec time to our Game
SendKeyDInput(DIK_A, 1000);
}
}
return 0;
}
void SendKeyDInput(byte DIK, DWORD time)
{
KeyBuffer[DIK].Key = DIK;
KeyBuffer[DIK].TTL = time;
KeyBuffer[DIK].StartTime = GetTickCount();
}
HRESULT __stdcall hkGetDeviceState(LPDIRECTINPUTDEVICE lpDevice, DWORD cbData, LPVOID *lpvData)
{
HRESULT hResult = DI_OK;
static BYTE buffer[256];
int key_count = 0;
for (int i = 0; i<256; i++)
{
if (KeyBuffer[i].Key != 0 && KeyBuffer[i].TTL>0 && KeyBuffer[i].StartTime != 0)
{
if (GetTickCount() > KeyBuffer[i].StartTime + KeyBuffer[i].TTL && KeyBuffer[i].isDown)
{
KeyBuffer[i].Key = 0;
KeyBuffer[i].StartTime = 0;
KeyBuffer[i].TTL = 0;
KeyBuffer[i].isDown = false;
buffer[KeyBuffer[i].Key] = 0;
}
else {
KeyBuffer[i].isDown = true;
buffer[KeyBuffer[i].Key] = 0x80;
key_count += 1;
add_log("Sending Key %x for %i milliseconds count: %i", KeyBuffer[i].Key, KeyBuffer[i].TTL, key_count);
}
}
}
if (key_count != 0)
{
cbData = 256;
memcpy(lpvData, buffer, cbData);
}
else {
hResult = pGetDeviceState(lpDevice, cbData, lpvData);
}
return hResult;
}
//Creates a Logfile in the Game Directory
void add_log(char* format, ...)
{
HANDLE filehandle;
DWORD dwReadBytes;
char buffer[2048];
char writebuffer[2048];
va_list args;
va_start(args, format);
vsprintf_s(buffer, format, args);
filehandle = CreateFile(L"Log.txt", GENERIC_WRITE, 0, 0, OPEN_ALWAYS, 0, 0);
SetFilePointer(filehandle, 0, 0, FILE_END);
sprintf_s(writebuffer, 2048, "Log Added: %s\r\n", buffer);
WriteFile(filehandle, writebuffer, strlen(writebuffer), &dwReadBytes, 0);
CloseHandle(filehandle);
}
The only issue in this code is when I attempt to send input, it doesn't go through. I've gotten some help and narrowed down a solution to this, which was: "Try GetDeviceState hk just memset(buffer, 0, size) or SendDeviceData". I've searched around a bit and I've been unable to find more on how to implement this solution and I'm stumped.
Could one of you kind people show me how I could use this information to fix this base? I'd be extremely grateful, thanks.
When unhandled exception occured i want to print a stacktrace instead of just terminating. I've tried to do that using SetUnhandledExceptionFilter:
SetUnhandledExceptionFilter(UnhandledException);
...
LONG WINAPI UnhandledException(LPEXCEPTION_POINTERS exceptionInfo)
{
printf("An exception occurred which wasn't handled!\nCode: 0x%08X\nAddress: 0x%08X",
exceptionInfo->ExceptionRecord->ExceptionCode,
exceptionInfo->ExceptionRecord->ExceptionAddress);
return EXCEPTION_EXECUTE_HANDLER;
}
This code, i've found, works fine. However there are no addition information because ExceptionCode and ExceptionAddress are printed in system "Event Viewer" anyway.
If it is possible to print a full stack trace so I can determine the exact point where exception occured?
I've found this code https://code.google.com/p/m0d-s0beit-sa/source/browse/src/main.cpp?r=9ceb4fec21d647b169c72851d7882bef2b9c5a8a It partly solves my problem. Only method where exception occured is printed. But type of exception and line number is not printed.
Here's some stack-walk code for Windows I wrote some years ago. Here's the kind of output it produces:
Walking stack.
0 DebugBreak
1 ThreadFunc2 e:\c\source\stackwalk2a.cpp(72)
2 ThreadFunc1 e:\c\source\stackwalk2a.cpp(79)
3 TargetThread e:\c\source\stackwalk2a.cpp(86)
4 BaseThreadInitThunk
5 RtlUserThreadStart
End of stack walk.
The main thing that's missing is anything about the exception type. If you're talking about a native structured/vectored exception, I'm pretty sure that should be retrievable too. Retrieving types of C++ exceptions might be a little more difficult (but I'm not really sure -- it might be pretty easy).
#include <windows.h>
#include <winnt.h>
#include <string>
#include <vector>
#include <Psapi.h>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <iterator>
#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "dbghelp.lib")
// Some versions of imagehlp.dll lack the proper packing directives themselves
// so we need to do it.
#pragma pack( push, before_imagehlp, 8 )
#include <imagehlp.h>
#pragma pack( pop, before_imagehlp )
struct module_data {
std::string image_name;
std::string module_name;
void *base_address;
DWORD load_size;
};
typedef std::vector<module_data> ModuleList;
HANDLE thread_ready;
bool show_stack(std::ostream &, HANDLE hThread, CONTEXT& c);
DWORD __stdcall TargetThread( void *arg );
void ThreadFunc1();
void ThreadFunc2();
DWORD Filter( EXCEPTION_POINTERS *ep );
void *load_modules_symbols( HANDLE hProcess, DWORD pid );
int main( void ) {
DWORD thread_id;
thread_ready = CreateEvent( NULL, false, false, NULL );
HANDLE thread = CreateThread( NULL, 0, TargetThread, NULL, 0, &thread_id );
WaitForSingleObject( thread_ready, INFINITE );
CloseHandle(thread_ready);
return 0;
}
// if you use C++ exception handling: install a translator function
// with set_se_translator(). In the context of that function (but *not*
// afterwards), you can either do your stack dump, or save the CONTEXT
// record as a local copy. Note that you must do the stack dump at the
// earliest opportunity, to avoid the interesting stack-frames being gone
// by the time you do the dump.
DWORD Filter(EXCEPTION_POINTERS *ep) {
HANDLE thread;
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
GetCurrentProcess(), &thread, 0, false, DUPLICATE_SAME_ACCESS);
std::cout << "Walking stack.";
show_stack(std::cout, thread, *(ep->ContextRecord));
std::cout << "\nEnd of stack walk.\n";
CloseHandle(thread);
return EXCEPTION_EXECUTE_HANDLER;
}
void ThreadFunc2() {
__try { DebugBreak(); }
__except (Filter(GetExceptionInformation())) { }
SetEvent(thread_ready);
}
void ThreadFunc1(void (*f)()) {
f();
}
// We'll do a few levels of calls from our thread function so
// there's something on the stack to walk...
//
DWORD __stdcall TargetThread(void *) {
ThreadFunc1(ThreadFunc2);
return 0;
}
class SymHandler {
HANDLE p;
public:
SymHandler(HANDLE process, char const *path=NULL, bool intrude = false) : p(process) {
if (!SymInitialize(p, path, intrude))
throw(std::logic_error("Unable to initialize symbol handler"));
}
~SymHandler() { SymCleanup(p); }
};
#ifdef _M_X64
STACKFRAME64 init_stack_frame(CONTEXT c) {
STACKFRAME64 s;
s.AddrPC.Offset = c.Rip;
s.AddrPC.Mode = AddrModeFlat;
s.AddrStack.Offset = c.Rsp;
s.AddrStack.Mode = AddrModeFlat;
s.AddrFrame.Offset = c.Rbp;
s.AddrFrame.Mode = AddrModeFlat;
return s;
}
#else
STACKFRAME64 init_stack_frame(CONTEXT c) {
STACKFRAME64 s;
s.AddrPC.Offset = c.Eip;
s.AddrPC.Mode = AddrModeFlat;
s.AddrStack.Offset = c.Esp;
s.AddrStack.Mode = AddrModeFlat;
s.AddrFrame.Offset = c.Ebp;
s.AddrFrame.Mode = AddrModeFlat;
return s;
}
#endif
void sym_options(DWORD add, DWORD remove=0) {
DWORD symOptions = SymGetOptions();
symOptions |= add;
symOptions &= ~remove;
SymSetOptions(symOptions);
}
class symbol {
typedef IMAGEHLP_SYMBOL64 sym_type;
sym_type *sym;
static const int max_name_len = 1024;
public:
symbol(HANDLE process, DWORD64 address) : sym((sym_type *)::operator new(sizeof(*sym) + max_name_len)) {
memset(sym, '\0', sizeof(*sym) + max_name_len);
sym->SizeOfStruct = sizeof(*sym);
sym->MaxNameLength = max_name_len;
DWORD64 displacement;
if (!SymGetSymFromAddr64(process, address, &displacement, sym))
throw(std::logic_error("Bad symbol"));
}
std::string name() { return std::string(sym->Name); }
std::string undecorated_name() {
std::vector<char> und_name(max_name_len);
UnDecorateSymbolName(sym->Name, &und_name[0], max_name_len, UNDNAME_COMPLETE);
return std::string(&und_name[0], strlen(&und_name[0]));
}
};
bool show_stack(std::ostream &os, HANDLE hThread, CONTEXT& c) {
HANDLE process = GetCurrentProcess();
int frame_number=0;
DWORD offset_from_symbol=0;
IMAGEHLP_LINE64 line = {0};
SymHandler handler(process);
sym_options(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
void *base = load_modules_symbols(process, GetCurrentProcessId());
STACKFRAME64 s = init_stack_frame(c);
line.SizeOfStruct = sizeof line;
IMAGE_NT_HEADERS *h = ImageNtHeader(base);
DWORD image_type = h->FileHeader.Machine;
do {
if (!StackWalk64(image_type, process, hThread, &s, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
return false;
os << std::setw(3) << "\n" << frame_number << "\t";
if ( s.AddrPC.Offset != 0 ) {
std::cout << symbol(process, s.AddrPC.Offset).undecorated_name();
if (SymGetLineFromAddr64( process, s.AddrPC.Offset, &offset_from_symbol, &line ) )
os << "\t" << line.FileName << "(" << line.LineNumber << ")";
}
else
os << "(No Symbols: PC == 0)";
++frame_number;
} while (s.AddrReturn.Offset != 0);
return true;
}
class get_mod_info {
HANDLE process;
static const int buffer_length = 4096;
public:
get_mod_info(HANDLE h) : process(h) {}
module_data operator()(HMODULE module) {
module_data ret;
char temp[buffer_length];
MODULEINFO mi;
GetModuleInformation(process, module, &mi, sizeof(mi));
ret.base_address = mi.lpBaseOfDll;
ret.load_size = mi.SizeOfImage;
GetModuleFileNameEx(process, module, temp, sizeof(temp));
ret.image_name = temp;
GetModuleBaseName(process, module, temp, sizeof(temp));
ret.module_name = temp;
std::vector<char> img(ret.image_name.begin(), ret.image_name.end());
std::vector<char> mod(ret.module_name.begin(), ret.module_name.end());
SymLoadModule64(process, 0, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size);
return ret;
}
};
void *load_modules_symbols(HANDLE process, DWORD pid) {
ModuleList modules;
DWORD cbNeeded;
std::vector<HMODULE> module_handles(1);
EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded);
module_handles.resize(cbNeeded/sizeof(HMODULE));
EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded);
std::transform(module_handles.begin(), module_handles.end(), std::back_inserter(modules), get_mod_info(process));
return modules[0].base_address;
}