How to call scanf_s in assembly to input a char? - visual-c++

this is part of code ("call scanf_s" to input a int)
but how to call scanf_s to input a char?
char format[]="%d"; //format string for the scanf function
int first;
_asm{
lea eax,first
push eax
lea eax,format; 读取第一个number
push eax
call scanf_s
add esp,8
mov eax,dword ptr [first]
push eax
lea eax,format
push eax
call printf
add esp,8
}

scanf_s needs an additional parameter for characters. From the Microsoft manual:
scanf_s and wscanf_s require the buffer size to be specified for all
input parameters of type c, C, s, S, or string control sets that are
enclosed in []. The buffer size in characters is passed as an
additional parameter immediately following the pointer to the buffer
or variable.
The C form of this function looks like scanf_s ("%c",&char,1);. Push the arguments from right to left in assembly:
#include <stdio.h>
int main ( void )
{
char scanf_fmt[] = "%c";
char printf_fmt[] = "%c\n";
char character;
_asm
{
push 1 // Buffer size, you can also write `push size character`
lea eax, character
push eax // Pointer to character
lea eax, scanf_fmt
push eax // Pointer to format string
call scanf_s
add esp, 12 // Clean up three pushes
movzx eax, byte ptr [character] // MOVZX: Load one unsigned byte into a 32-bit-register
push eax // Character as value
lea eax, printf_fmt
push eax // Pointer to format string
call printf
add esp,8 // Clean up two pushes
}
return 0;
}

Related

x86 inline assembly language how to flush keyboard input cache

I want to write an input validation, users can input name with whitespace, if it is null or exceed the maximum array length, it will jmp to the beginning. However, when the input is too long, \n would be left over the second turn, which means scanf_s would receive the value automatically in the second turn. So I imagine is there a method like Java fflush in the inline assembly language to clear keyboard input every turn? This is my code:
char inputName[] = "%20[^\n]";
char name[20];
int validNum;
_asm{
startInput:
lea eax, name
push eax
call scanf_s //this is the problem part
add esp, 8
computeLength:
lea ebx, name
...
inc validNum
cmp [ebx], '\0'
je validate
validate:
cmp validNum, 20
jg startInput
}

(VC++) Runtime Check for Uninitialized Variables: How is the test Implemented?

I'm trying to understand what this test does exactly. This toy code
int _tmain(int argc, _TCHAR* argv[])
{
int i;
printf("%d", i);
return 0;
}
Compiles into this:
int _tmain(int argc, _TCHAR* argv[])
{
012C2DF0 push ebp
012C2DF1 mov ebp,esp
012C2DF3 sub esp,0D8h
012C2DF9 push ebx
012C2DFA push esi
012C2DFB push edi
012C2DFC lea edi,[ebp-0D8h]
012C2E02 mov ecx,36h
012C2E07 mov eax,0CCCCCCCCh
012C2E0C rep stos dword ptr es:[edi]
012C2E0E mov byte ptr [ebp-0D1h],0
int i;
printf("%d", i);
012C2E15 cmp byte ptr [ebp-0D1h],0
012C2E1C jne wmain+3Bh (012C2E2Bh)
012C2E1E push 12C2E5Ch
012C2E23 call __RTC_UninitUse (012C10B9h)
012C2E28 add esp,4
012C2E2B mov esi,esp
012C2E2D mov eax,dword ptr [i]
012C2E30 push eax
012C2E31 push 12C5858h
012C2E36 call dword ptr ds:[12C9114h]
012C2E3C add esp,8
012C2E3F cmp esi,esp
012C2E41 call __RTC_CheckEsp (012C1140h)
return 0;
012C2E46 xor eax,eax
}
012C2E48 pop edi
012C2E49 pop esi
012C2E4A pop ebx
012C2E4B add esp,0D8h
012C2E51 cmp ebp,esp
012C2E53 call __RTC_CheckEsp (012C1140h)
012C2E58 mov esp,ebp
012C2E5A pop ebp
012C2E5B ret
The 5 lines emphasized are the only ones removed by properly initializing the variable i. The lines 'push 12C2E5Ch, call __RTC_UninitUse' call the function that display the error box, with a pointer to a string containing the variable name ("i") as an argument.
What I can't understand are the 3 lines that perform the actual test:
012C2E0E mov byte ptr [ebp-0D1h],0
012C2E15 cmp byte ptr [ebp-0D1h],0
012C2E1C jne wmain+3Bh (012C2E2Bh)
It would have seemed the compiler is probing the stack area of i (setting a byte to zero and immediately testing whether it's zero), just to be sure it isn't initialized somewhere it couldn't see during build. However, the probed address, ebp-0D1h, has little to do with the actual address of i.
Even worse, it seems if there were such an external (other thread?) initialization that did initialize the probed address but to zero, this test would still shout about the variable being uninitialized.
What's going on? Maybe the probe is meant for something entirely different, say to test if a certain byte is writable?
[ebp-0D1h] is a temporary variable used by the compiler to track "initialized" status of variables. If we modify the source a bit, it will be more clear:
int _tmain(int argc, _TCHAR* argv[])
{
int i, j;
printf("%d %d", i, j);
i = 1;
printf("%d %d", i, j);
j = 2;
return 0;
}
Produces the following (irrelevant parts skipped):
mov DWORD PTR [ebp-12], -858993460 ; ccccccccH
mov DWORD PTR [ebp-8], -858993460 ; ccccccccH
mov DWORD PTR [ebp-4], -858993460 ; ccccccccH
mov BYTE PTR $T4694[ebp], 0
mov BYTE PTR $T4693[ebp], 0
In prolog, variables are filled with 0xCC, and two tracking variables (one for i and one for j) are set to 0.
; 7 : printf("%d %d", i, j);
cmp BYTE PTR $T4693[ebp], 0
jne SHORT $LN3#main
push OFFSET $LN4#main
call __RTC_UninitUse
add esp, 4
$LN3#main:
cmp BYTE PTR $T4694[ebp], 0
jne SHORT $LN5#main
push OFFSET $LN6#main
call __RTC_UninitUse
add esp, 4
$LN5#main:
mov eax, DWORD PTR _j$[ebp]
push eax
mov ecx, DWORD PTR _i$[ebp]
push ecx
push OFFSET $SG4678
call _printf
add esp, 12 ; 0000000cH
This corresponds roughly to:
if ( $T4693 == 0 )
_RTC_UninitUse("j");
if ( $T4694 == 0 )
_RTC_UninitUse("j");
printf("%d %d", i, j);
Next part:
; 8 : i = 1;
mov BYTE PTR $T4694[ebp], 1
mov DWORD PTR _i$[ebp], 1
So, once i is intialized, the tracking variable is set to 1.
; 10 : j = 2;
mov BYTE PTR $T4693[ebp], 1
mov DWORD PTR _j$[ebp], 2
Here, the same is happening for j.
Here is my guess: the compiler probably allocates flags in memory showing the initialization status of variables. In your case for variable i this is a single byte at [ebp-0D1h]. The zeroing of this byte means i is not initialized. I assume if you initialize i this byte will be set to non-zero. Try something run-time like this: if (argc > 1) i = 1; This should generate code instead of omitting the whole check. You can also add another variable, and see if you get two different flags.
The zeroing of the flag and the testing just happen to be consecutive in this case, but that might not always be the case.
C7060F000055 mov dword ptr [esi],5500000Fh
C746048BEC5151 mov dword ptr [esi+0004],5151EC8Bh
b. And one of its later generations:
BF0F000055 mov edi,5500000Fh
893E mov [esi],edi
5F pop edi
52 push edx
B640 mov dh,40
BA8BEC5151 mov edx,5151EC8Bh
53 push ebx
8BDA mov ebx,edx
895E04 mov [esi+0004],ebx
c. And yet another generation with recalculated ("encrypted") "constant" data:
BB0F000055 mov ebx,5500000Fh
891E mov [esi],ebx
5B pop ebx
51 push ecx
B9CB00C05F mov ecx,5FC000CBh
81C1C0EB91F1 add ecx,F191EBC0h ; ecx=5151EC8Bh

Inline assembly operand size conflict

I am working on this for class, and as per the instructors guidelines we have to do the program using inline c++. The purpose of the program is to take a string of any length and reverse it. The error I'm getting is an operand size conflict and from what I can tell it's in the first line of the __asm block, there could be other issues but the only one that shows up in visual studio is the conflict. Here is my asm block
int _tmain(int argc, _TCHAR* argv[])
{
char string[] = "Hi There!";
__asm
{ // reverse a string of any length
lea ecx, string
lea eax, string
mov esi, eax // esi points to start of string
add eax, ecx
mov edi, eax
dec edi // edi points to end of string
shr ecx, 1 // ecx is count (length/2)
jz done // if string is 0 or 1 characters long, done
reverseLoop:
mov al, [esi] // load characters
mov bl, [edi]
mov [esi], bl // and swap
mov [edi], al
inc esi // adjust pointers
dec edi
dec ecx // and loop
jnz reverseLoop
done:
}
printf(string);
return 0;
}
I made the changes now I am getting this: Unhandled exception at 0x00e71416 in String Reverse.exe: 0xC0000005: Access violation reading location 0x0087ef6f. Based on other suggestions I have tried I have still not be able to get it to run properly. I think the issue might be in the registers I'm referencing or the add eax line, but I'm not really sure.
mov ecx, [string]
"string" is an array of char, you are trying to move 8 bits into a 32-bit register. If is was a global variable you'd use the offset keyword. But it is not, it is stored on the stack. Which requires you to use the LEA instruction (load effective address), like this:
lea ecx,string
which the compiler automatically translates into something like:
lea ecx,[ebp-20]
with the -20 adjustment depending on where it is located on the stack. The ECX register now points to the first char in the string.

how to set labels in inline assembly?

how in c++ visual can i set labels for when i need to use inline assembly, so it would look like something like this for example...
__asm
{
PUSH EAX
PUSH VAR1
MOV ECX,DWORD PTR DS:[VAR2]
CALL DWORD PTR DS:[VAR3]
JMP VAR4
}
where the VAR varables link to a value or address?
i have tried the following
DWORD VAR2 = 0x991770; //0x991770 is the location of the function
__asm
{
..code
MOV ECX,DWORD PTR DS:[VAR2]
..code
}
but then the app crashes, how is this done?
Use offset variableName to access variables from inline assembly. See reference here.
Example:
char format[] = "%s %s\n";
char hello[] = "Hello";
char world[] = "world";
int main( void )
{
__asm
{
mov eax, offset world
push eax
mov eax, offset hello
push eax
mov eax, offset format
push eax
call printf
//clean up the stack so that main can exit cleanly
//use the unused register ebx to do the cleanup
pop ebx
pop ebx
pop ebx
}
}
C variable names are visible in inline assembly. So if you need data access, just write the var name:
int var2 = 3;
__asm
{
mov ecx, var2
That will compile to the appropriate memory access statement.
For code labels - you just declare them, like in real assembly:
Label1:
mov ecx, 0
jmp Label1
External functions are seen as labels, too. Name mangling applies, though.
If you need the numeric value of the current IP as a general purpose register, there's no direct command, but a very simple workaround is available:
call Next
Next:
pop eax ; eax now is the value of IP at the current point
Oh, and forget about the ds: stuff. You're in Flatland now - check your segment registers at the door.

Microsoft inline assembly and references or Why does BYTE PTR [ByteRef] not work in this situation?

Okay so I have a C++ function in which I am trying to use inline assembly
void ToggleBit(unsigned char &Byte, unsigned int Bit)
{
/* In C:
* Byte ^= (1<<Bit);
*/
__asm
{
push edx
push ecx
mov ecx, Bit
xor edx, edx
mov edx, 1
sal dl, cl
xor BYTE PTR [Byte], dl
pop ecx
pop edx
}
}
This should work, right? Since Byte is a reference (which is essentially a constant pointer), it must be dereferenced to access the data... but it didn't work!
Upon debugging the following code:
mov edx, Byte
;edx = 0x0040f9d3
mov bl, BYTE PTR [Byte]
;bl = 0xd3
I don't understand why this would happen at all.
As you say, a reference is the same as a pointer in assembly. To access the reference/pointer, you must first read the pointer value, and then dereference it:
mov ecx, Byte ; Or mov ecx, [Byte] which is the same thing
xor [ecx], dl
When you access the value at BYTE PTR [Byte], it accesses the first byte of the pointer value (the pointed-to address) instead of the pointed-to value.

Resources