I'm trying to figure out how to use DB variables from ASM into Inline ASM C++
I have this ASM code:
filename db "C:\imagen.bmp"
eti0:
mov ah,3dh
mov al,0
mov dx,offset filename
int 21h
and in C++:
//ASCII of C:\imagen.bmp plus zero in the end because of int 21h
int filename=6758921051099710310111046981091120;
asm{
mov ah,3dh
mov al,0
mov dx,offset filename
int 21h
}
Is this is correct?
The type int can only hold a 16-bit signed integer and the number you tried to assign to filename is way outside its range. As int variables are two bytes long, they're not all that useful for storing file names. Instead you should store the name in an array of char like this:
char filename[] = "C:\\imagen.bmp";
The array will include a zero byte as its final element, as normal for strings in C++.
You could also replace entire thing with:
int handle;
_dos_open("C:\\imagen.bmp", 0, &handle);
Related
Hello All!
I'm doing a MASM course and I got into this exercise.
I have this simple assembly code:
.386
.model flat,c
.data
quote byte "Machines do feel", 0
message byte SIZEOF quote DUP(0),0
.code
start proc
mov esi,0
mov ecx,SIZEOF quote
LP:
mov al,quote[esi]
mov message[esi],al
inc esi
loop LP
ret
start endp
end
And I want to write a C++ program that can "printf" the variable "message".
How can I do this?
I tryed to add:
mov eax, DWORD ptr [message]
To the ".asm" file to store the address of the message variable on the register returned by the function and then I wrote this program to try to printf the values:
#include <iostream>
extern "C" char *start();
int main(){
char *message = start();
for(int i = 0x0; i < sizeof(message)/sizeof(char); i++){
printf("%s", message[i]);
}
return 0x0;
}
But when I try to run it I get the error:
Unhandled page fault on read access to 6863614D at address 0040162E (thread 0024), starting debugger...
0024:err:seh:start_debugger Couldn't start debugger L"winedbg --auto 32 68" (2)
Can you please explain me how can I print the values of the ".asm" file "message" variable?
And can also show me different methods to do this?
Thank you so much, have a nice coding!
I am struggling to understand if I am doing this the correct way and if this is the (only) best solution.
The project I am working on is using a Three-Dimensional Array to hold and use lots of data. One part of the "data" is DWORD type and I must have a safe conversion from/to DWORD/BYTE.
The BYTE (c style) array looks like this:
BYTE array_data[150][5][255] =
{
{
{ // bytes },
{ 0x74,0x21,0x54,0x00 }, // This is converted from DWORD like: 0x00542174
{ // bytes },
{ // bytes },
{ // bytes },
},
};
The (only) way to convert from DWORD to BYTE(s) I found:
DWORD dword_data;
char byte_array[4];
*(DWORD*)byte_array = dword_data; // byte_array becomes {0x74, 0x21, 0x54, 0x00}
wchar_t temp[256];
wsprintfW(temp, L"{0x%02x,0x%02x,0x%02x,0x%02x}, // This is converted from DWORD like: 0x%.8X\n", (BYTE)byte_array[0], (BYTE)byte_array[1], (BYTE)byte_array[2], (BYTE)byte_array[3], (DWORD)dword_data);
From I understand DWORD is 4 BYTE so that's why the char max length is 4. (correct me if I`m wrong?)
Then to convert back to DWORD from BYTE(s):
//Convert an array of four bytes into a 32-bit integer.
DWORD getDwordFromBytes(BYTE* b)
{
return (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
};
printf("dword_data: 0x%.8X\n", getDwordFromBytes(array_data[0][1]));
Which prints out fine: 0x00542174.
So my question is, is all this correct and safe ? Because I will have lots of data in the array and the DWORD/BYTE conversion for me is imperative, it must be accurate.
Please advise and correct me where I`m doing things wrong, I would very much appreciate it!
This code
DWORD dword_data;
char byte_array[4];
*(DWORD*)byte_array = dword_data;
is undefined behavior according to the C++ standard. Some compilers may allow it as an extension, but unless you want to be surprised when you change a compiler or command line options, don't use it.
The correct way is:
DWORD dword_data;
BYTE byte_array[sizeof(DWORD)];
memcpy(byte_array, &dword_data, sizeof(DWORD));
Don't worry about efficiency: this memcpy will be optimized out by any decent compiler.
In C++20 you'll be able to be more eloquent:
auto byte_array = std::bit_cast<std::array<BYTE, sizeof(DWORD)>>(dword_data);
The backwards conversion should also be done using memcpy to be endianness-independent: your getDwordFromBytes will fail to produce the original dword_data on a big-endian machine.
DWORD is 32-bit unsigned integer.
typedef unsigned long DWORD, *PDWORD, *LPDWORD;
32-bit means 4 bytes, because each byte is 8 bit. And 4*8=32
https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/262627d8-3418-4627-9218-4ffe110850b2
The problem will happen when you send your byte array to some code that expects to see those bytes in reversed order (different endianness). You would then need to reverse it.
DWORD is windows specific typedef, and all windows are little-endian, so I think it's safe to use this code as is, if you process data on the same machine.
I've got a function returning a binary representation of a byte:
std::string ToBinary(unsigned char &Num)
{
char str[8];
char Symb = 0;
int i = 0;
while (i<8)
{
_asm
{
//push al
shr byte[Num], 1
mov al, 0
adc al, 30h
mov byte[Symb], al
//pop al
}
str[7-i] = Symb;
i++;
}
return std::string(str);
}
And it's call:
std::string BinOut = ToBinary(ByteValue);
The problem is that instead of getting an 8-char string it returns 14-char string. Obviously, inside the function str shows correct value. How do I make it return 8 characters?
The constructor of std::string which accepts a pointer to char requires that the pointed string is null terminated. Your str is not null terminated and so the behaviour of the program is undefined.
You can either
Use a char[9] and set the last character to '\0'. This works only if the str doesn't contain any zero bytes since the first one would be the terminator.
Or use the constructor std::string(char *s, std::size_t count) which doesn't have such requirement.
The problem is caused because your character array does not contain a terminating null character. One solution is to allocate an array with one extra character so you can terminate it with null:
char str[9]
//...
str[8] = '\0'
Alternatively, you can use an overloaded string constructor that allows you to pass in a parameter for the number of characters to use from the input array:
std::string(str, 8);
I am working on a C++ and external asm code. It is a requirement for us to work with external ASM libraries. The problem is that, I am having difficulty passing the string from the c++ side to asm. I am sure I am making some mistake in accessing the string on the asm end.
I basically read from a text file, word - by - word. Then I want to pass each word onto the ASM side and process it for some statistics.
Suppose I retrieved a word from the file and it is stored in
string wordFromFile = "America";
processWord(wordFromFile, wordFromFile.size()) //processFromWord is the ASM side function
;;ASM SIDE
;;The doubt I have (first of all all) is how do I declare the arguments on the ASM SIDE
ProcessWordUpperCase PROC C, wordFile :BYTE, len :DWORD
OR
ProcessWordUpperCase PROC C, buffer :DWORD, len :DWORD
How should I? And one more thing, in the function I am going to access the string by each letter. What do you advise here?
Here is a skeleton just counting the length of the string where you could put youir code.
toupper.cpp
extern "C"
{
int ProcessWordUpperCase(const char *wordFile, int arraySize);
};
int main(int argc, char*arg[])
{
char t[100];
int res;
res = ProcessWordUpperCase(t, sizeof(t));
std::string s = "myvalue";
res = ProcessWordUpperCase(s.c_str(), s.length());
return 0;
}
toupper.asm
.486
.model flat, C
option casemap :none
.code
ProcessWordUpperCase PROC, wordFile:PTR BYTE, arrayLen:DWORD
LOCAL X:DWORD
push ebx
push esi
push edi
mov edi, wordFile
xor eax, eax
dec edi
dec eax
##StringLoop:
inc edi
inc eax
cmp byte ptr [edi], 0
jne ##StringLoop
; return length of string
pop edi
pop esi
pop ebx
ret
ProcessWordUpperCase ENDP
END
A simple trick to get the skeleton of a function is to tell VS to output ASM files.
How to do it:
Crete a new source file with an empty function that has the prototype you want
e.g. int foo(const char* s, int bar) { return *s + bar; }
Right click on the a source file and select Properties->C/C++->Output Files->Assembler Output.
Select a value that suits you.
build and look at the generated ASM file.
The generated asm file includes some security checks that can disable by playing with the compilation flags for this file.
From the C side:
I'd do it like that: pass the string as an array, alongside with a number of fields in the array. The program will write the pointer to the very beginning of the array to the stack, so if you want to retrieve the very first char in the string, just refer to it as
mov eax, [adress of the pointer on stack]
What I am doing is injecting a DLL into a running process. I then proceed to check some informations about that process, such as versions etc. My problem is I cannot seem to access a string in the assembly file, that contains the revision number I want to doublecheck. Here is what I have so far:
__declspec(naked) void CheckBuild()
{
char* revision;
__asm {
sub esp, __LOCAL_SIZE
pushad
pushfd
mov revision, dword ptr 0x5F5200
}
printf("Detected revision ID: %u\n", revision);
__asm {
popfd
popad
add esp, __LOCAL_SIZE
retn
}
}
For this training stuff, the address of the string, that I get through IDA and that I checked using CheatEngine and OllyDbg, is constant.
However, no matter what I try, I always get 0x5F5200 back in decimal, which is definitely not what I expect. I almost tried everything, including lea and others, but I still don't get the valid string.
Can anyone point me to the correct direction ?
you are missing the "dereferencing":
mov revision, dword ptr [0x5F5200]
which isn't a valid instruction since it has two indirects, so
mov eax, dword ptr [0x5F5200]
mov revision, eax
if the value is indeed a string, there's something else wrong:
if the string is stored at 0x5F5200, you would simply use
printf("Detected revision ID: %s\n", 0x5F5200)
if the address of the string is stored at 0x5F5200, you would use
printf("Detected revision ID: %s\n", revision)
String format
If the string is unicode, you would use
printf("Detected revision ID: %S\n", revision);
(note that with wprintf, it's the other way 'round: %s for a wide character string, and %s for a char string).
Finally, if the string is not guaranteed to be zero-terminated but has a fixed length, you need to copy from the address to a local buffer and ensure zero termination before the print.