little bit of a problem here, tried to create assembly code which converts strings to integers. Unfortunately, I cannot find the reason why it "breaks", I input 54321 and it converts to 543418. All goes OK till 2 and then it prints random numbers instead of printing the same 54321. I already spent an hour debugging, but cannot find the cause of this problem, maybe I'm blind?
#include <stdio.h>
#include <string.h>
#include "stdlib.h"
int main(int argc, char** argv)
{
int result;
char* argv1 = argv[1];
if (argc < 2)
{
printf("Parameter is not provided*/\n");
return(0);
}
__asm
{
push eax
push ebx
push ecx
mov ecx, argv1 // 54321 --> 5 *10+4=54 *10+3=543 *10+2=5432 *10+1=54321
mov ebx, 10 // register in which i put value
mov al, byte ptr[ecx] // byte of string to al
sub al, '0'
loop_begins:
mov dl, byte ptr [ecx] // byte of string to dl
cmp dl, 0 // compare to zero (string end)
je loop_ends // if zero byte (string end)
// here we make char out of int
xor edx, edx // zero edx
mul ebx // edx: eax = eax * ebx
inc ecx // ecx points to next char in string
mov dl, byte ptr [ecx] // dl - edx part, other register
sub dl, '0' // same, but other element
add eax, edx // addition (here we get 54)
xor edx, edx // zero edx
jmp loop_begins // and loop to next char
loop_ends:
mov [result], eax // answer to variable result
pop ecx
pop ebx
pop eax
};
printf("Answer is %d\n", result);
system("PAUSE");
}
I made a few modifications (<mod> in comments) to your code keeping the spirit (also according to my weak and unused for a long time asm knowledge ):
__asm
{
push eax // current value / result
push ebx // 10
push ecx // string
xor eax, eax // <mod> : reset eax
mov ebx, 10 // register in which i put value
mov ecx, argv1 // 54321 --> 5 *10+4=54 *10+3=543 *10+2=5432 *10+1=54321
// <mod> : unnecessary
// mov al, byte ptr[ecx] // byte of string to al
// sub al, '0'
loop_begins:
mov dl, byte ptr [ecx] // byte of string to dl
cmp dl, 0 // compare to zero (string end)
je loop_ends // if zero byte (string end)
// here we make char out of int
// xor edx, edx // zero edx // <mod> : unnecessary
mul ebx // edx: eax = eax * ebx
mov dl, byte ptr [ecx] // dl - edx part, other register
sub dl, '0' // same, but other element
add eax, edx // addition (here we get 54)
// xor edx, edx // zero edx // <mod> : unnecessary
inc ecx // ecx points to next char in string // <mod> moved as suggested in comments
jmp loop_begins // and loop to next char
loop_ends:
mov [result], eax // answer to variable result
pop ecx
pop ebx
pop eax
};
Related
I am writing an assembly function callable from C++ that will read the CPU Vendor ID. Here is the function signature:
extern "C" void GetVendorID(const char* id);
Here is how I am calling it:
char vendorID[13];
GetVendorID(vendorID);
vendorID[12] = '\0';
Here is the important parts of the assembly:
global GetVendorID
GetVendorID:
push ebp
mov ebp, esp
push eax
push ebx
push ecx
push edx
mov eax, 0
cpuid ; <- this instruction moves the vendor id into ebx, edx, ecx
mov eax, [ebp + 8] ; <- move the value of the char pointer parameter into eax
; I have verified that this instruction works by returning eax and comparing it to the
; address of the vendorID array
; start with ebx
mov byte [eax], bl ; <- move a character into the char array
inc eax ; <- increment the pointer
shl ebx, 8 ; <- shift ebx to get the next character in its least significant bits
mov byte [eax], bl ; <- repeat
inc eax
shl ebx, 8
mov byte [eax], bl
inc eax
shl ebx, 8
mov byte [eax], bl
inc eax
shl ebx, 8
; above is repeated for edx and ecx
pop edx
pop ecx
pop ebx
pop eax
mov esp, ebp
pop ebp
ret
The way the string is stored in the registers is weird. The first character is stored in the least significant byte of ebx, the next is stored in the second least significant byte, and so on. That is why I am doing the left shifts.
I have verified that ebx, edx, ecx do contain the correct values by returning them from the function and printing them out. They contain "GenuineIntel". However, the char array remains unchanged. It is full of zeroes after the function returns.
I am not really sure why this isn't working. Am I accessing the parameter incorrectly?
__asm { //
push eax //
push ecx //
movsx ecx, temp_char //
lea eax, EKey //
call encryptX // encrypt the character
mov temp_char, al //
pop ecx //
pop eax //
}
EChars[i] = temp_char; // Store encrypted char in the encrypted chars array
}
return;
// ---------------------------- start of ASM code ---------------------------------------------------------------encryptX: push ecx //push to manipulate
xchg eax, ecx //exchange values in eax and ecx / eax holds old ecx
neg al //twos complement least most eax byte (old ecx)
ror al, 1 //rotate right least most byte by 1 of eax
xor al, byte ptr[ecx] //exlcusive or least most byte against ecx value being pointed at
push edx //push edx onto stack for manipulatio
mov edx, eax //move eax into edx
xchg eax, ecx //swap values of ecx and eax
rol byte ptr[eax], 3 //rotate left the byte being pointed at 3 times
xor dl, byte ptr[eax] //xor the least byte by pointed value in eax
rol dl, 2 //rotate left the least byte in edx by 2
mov eax, edx //move edx value into eax
pop edx //pop values out
pop ecx //pop values out
ret //return
}
i have the task of implementing a standard call in this code - be that cdecl or std call
'mov eax, [ebp+8] // get first parameter that was pushed'
i understand the idea of pushing the pointers location but i am unsure of where i would tell the pointer to look.
be that mov eax, [ebp+4/8/12] or what have you
any help in telling me how i would do this would be greatly appreciated, similarly if one of you kind folk do solve this could an explanation be added
Thanks
I'm learning assembly programming and I've been tasked with converting a for loop (along with any array use) into assembly within my program.
The program simply takes an encryption key (EKey) and uses it to encrypt an array of letters (hello for example).
Here is the loop in C++:
void encrypt_chars(int length, char EKey)
{
char temp_char; // char temporary store
for (int i = 0; i < length; i++) // encrypt characters one at a time
{
temp_char = OChars[i]; // temp_char now contains the address values of the individual character
__asm
{
push eax // Save values contained within register to stack
push ecx
movzx ecx, temp_char
push ecx // Push argument #2
lea eax, EKey
push eax // Push argument #1
call encrypt
add esp, 8 // Clean parameters of stack
mov temp_char, al // Move the temp character into a register
pop ecx
pop eax
}
EChars[i] = temp_char; // Store encrypted char in the encrypted chars array
}
return;
// Inputs: register EAX = 32-bit address of Ekey,
// ECX = the character to be encrypted (in the low 8-bit field, CL).
// Output: register EAX = the encrypted value of the source character (in the low 8-bit field, AL).
__asm
{
encrypt:
push ebp // Set stack
mov ebp, esp // Set up the base pointer
mov eax, [ebp + 8] // Move value of parameter 1 into EAX
mov ecx, [ebp + 12] // Move value of parameter 2 into ECX
push edi // Used for string and memory array copying
push ecx // Loop counter for pushing character onto stack
not byte ptr[eax] // Negation
add byte ptr[eax], 0x04 // Adds hex 4 to EKey
movzx edi, byte ptr[eax] // Moves value of EKey into EDI using zeroes
pop eax // Pop the character value from stack
xor eax, edi // XOR character to give encrypted value of source
pop edi // Pop original address of EDI from the stack
rol al, 1 // Rotates the encrypted value of source by 1 bit (left)
rol al, 1 // Rotates the encrypted value of source by 1 bit (left) again
add al, 0x04 // Adds hex 4 to encrypted value of source
mov esp, ebp // Deallocate values
pop ebp // Restore the base pointer
ret
}
//--- End of Assembly code
}
I've looked at the disassembly code and used that to rewrite the ASM code. I typed in the disassembly code as follows however it gives the following errors: http://gyazo.com/3b6875c9e1207df61df4e95506af7ed6
Here is my code:
void encrypt_chars(int length, char EKey)
{
char temp_char;
__asm
{
mov DWORD PTR[rbp - 4], 0
jmp L2
L3:
mov eax, DWORD PTR[rbp - 4]
cdqe
cltq
// ERROR HERE ^ above: error C2400: inline assembler syntax error in 'opcode'; found 'newline'
movzx eax, BYTE PTR EChars[rax]
// ERROR HERE ^ above: error C2400: inline assembler syntax error in 'opcode'; found 'newline'
// another error ^ above: error C2424: '[' : improper expression in 'second operand'
mov BYTE PTR[rbp - 5], al
// OG code
push eax // Save values contained within register to stack
push ecx
movzx ecx, temp_char
push ecx // Push argument #2
lea eax, EKey
push eax // Push argument #1
call encrypt4
add esp, 8 // Clean parameters of stack
mov temp_char, al // Move the temp character into a register
pop ecx
pop eax
// end of OG code
mov eax, DWORD PTR[rbp - 4]
cdqe
movzx edx, BYTE PTR[rbp - 5] // ERROR HERE: error C2400: inline assembler syntax error in 'opcode'; found 'newline'
mov BYTE PTR DChars[rax], dl // ERROR HERE: error C2424: '[' : improper expression in 'first operand'
L2:
mov eax, DWORD PTR[rbp - 4]
cmp eax, DWORD PTR[rbp - 20]
jl L3
}
return;
__asm
{
encrypt4:
push ebp // Set stack
mov ebp, esp // Set up the base pointer
mov eax, [ebp + 8] // Move value of parameter 1 into EAX
mov ecx, [ebp + 12] // Move value of parameter 2 into ECX
push edi // Used for string and memory array copying
push ecx // Loop counter for pushing character onto stack
not byte ptr[eax] // Negation
add byte ptr[eax], 0x04 // Adds hex 4 to EKey
movzx edi, byte ptr[eax] // Moves value of EKey into EDI using zeroes
pop eax // Pop the character value from stack
xor eax, edi // XOR character to give encrypted value of source
pop edi // Pop original address of EDI from the stack
rol al, 1 // Rotates the encrypted value of source by 1 bit (left)
rol al, 1 // Rotates the encrypted value of source by 1 bit (left) again
add al, 0x04 // Adds hex 4 to encrypted value of source
mov esp, ebp // Deallocate values
pop ebp // Restore the base pointer
ret
}
//--- End of Assembly code
}
Would anyone be able to point out where I'm going wrong please? I'm finding this relatively difficult so step-by-step explanations are most welcome. Please let me know where I'm going wrong. Thanks x
EDIT:
My full code: http://pastebin.com/tP9Dgvpn
Try this:
void encrypt_chars(int length, char EKey, char *Msg)
{
int InLength = length;
int counter;
__asm
{
push eax // Counter
mov eax, 0 // Zero counter
push ebx // Value
mov ebx, InLength
jmp L2
L3:
mov counter, EAX
call encrypt4
inc eax // Increment counter.
L2:
cmp eax, ebx
jl L3 // Jump if we haven't reached our count.
pop ebx
pop eax
}
return;
__asm
{
encrypt4:
push eax
push ebx
push edi
mov ebx, counter
add ebx, Msg
mov al, [ebx] // Move character into al
CBW // Make word.
CWDE // Make Dword.
not byte ptr[EKey] // Negation
add byte ptr[EKey], 0x04 // Adds hex 4 to EKey
movzx edi, byte ptr[EKey] // Moves value of EKey into EDI using zeroes
xor eax, edi // XOR character to give encrypted value of source
pop edi // Pop original address of EDI from the stack
rol al, 1 // Rotates the encrypted value of source by 1 bit (left)
rol al, 1 // Rotates the encrypted value of source by 1 bit (left) again
add al, 0x04 // Adds hex 4 to encrypted value of source
mov [ebx], al
pop ebx
pop eax
ret
}
//--- End of Assembly code
}
I call it with this snippet:
EKey = 'i';
sprintf(OChars, "hello");
printf("%s\n", OChars);
encrypt_chars(sizeof(OChars), EKey, OChars);
printf("%s\n", OChars);
My output looks like this:
hello
╧4▀↑█⌐
This matches your output but all except the first character. I am convinced the algorithm looks correct and I can't spend any more time on it. I believe it can be differences in character sets. Try it out.
Good luck!
I am using some code from Github, but it won't compile. The debugger opens in the middle of the code compiling. This is a personal project and it would be really helpful if anyone could make useful edits to the code as I am new to assembly.
Here is the output that I am getting until the debugger opens:
'Assembly.exe': Loaded
'C:\Users\Mayank\Desktop\Assembly\Debug\Assembly.exe', Symbols loaded.
'Assembly.exe': Loaded 'C:\Windows\SysWOW64\ntdll.dll', Cannot find or
open the PDB file 'Assembly.exe': Loaded
'C:\Windows\SysWOW64\kernel32.dll', Cannot find or open the PDB file
'Assembly.exe': Loaded 'C:\Windows\SysWOW64\KernelBase.dll', Cannot
find or open the PDB file 'Assembly.exe': Loaded
'C:\Windows\SysWOW64\msvcr100d.dll', Symbols loaded. First-chance
exception at 0x011013fe in Assembly.exe: 0xC00000FD: Stack overflow.
Unhandled exception at 0x011013fe in Assembly.exe: 0xC00000FD: Stack
overflow.
Here is the code:
//
// main.cpp
// MergeSortC
//
// Copyright (c) 2012 Mayank. All rights reserved.
//
#include <iostream>
#include <cmath>
#include <stdio.h>
using namespace std;
const int ARRAYSIZE = 30;
int main()
{
int arr[ARRAYSIZE];
int temp_arr[ARRAYSIZE];
int number;
for(int x = 0; x < ARRAYSIZE; x++)
{
number = (rand() % 99) + 1;
arr[x] = number;
}
Merge_Sort:
__asm
{
// EAX - Array start
// ECX - array length
// Merge_Sort (first half)
// Length of the first half
// ECX /= 2
push ECX
shr ECX, 2
call Merge_Sort
pop ECX
// Merge_Sort (second half)
push arr
push EBX
push ECX
// Length of the second half
// ECX = ECX - ECX/2
mov EDX, ECX
shr EDX, 1
sub ARRAYSIZE, EDX
imul EDX, 4
// Start index of the second half
// EAX = EAX + (ECX/2) * 4
add arr, EDX
push EDX
call Merge_Sort
pop EDX
pop ECX
pop EBX
pop arr
pushad
// Merge (first half, second half)
// Length of first half = ECX/2
// Length of second half = ECX - ECX/2
mov EDX, ECX
shr ECX, 1
sub EDX, ECX
// Start of second half = EAX + (ECX/2) * 4
mov EBX, EAX
mov EDI, ECX
imul EDI, 4
add EBX, EDI
// Index of temp array = 0
sub EDI, EDI
call Merge
popad
// Copy back the merged array from temp_arr to arr
call Merge_Copy_Back_Temp
ret
};
Merge:
__asm
{
// Merge two arrays contents.
// The final merged array will be in temp_arr
// Merging is done recursively.
// Arguments:
// EAX - First array's start
// EBX - Second array's start
// ECX - Length of first array
// EDX - Length of second array
// EDI - Index in temp array
pushad
// Handle the cases where one array is empty
cmp ARRAYSIZE, 0
jz First_Array_Over
cmp EDX, 0
jz Second_Array_Over
// Compare first elements of both the arrays
push ARRAYSIZE
push EDI
mov ECX, [arr]
mov EDI, [ECX]
cmp ECX, EDI
pop EDI
pop ECX
// Pick which ever is the least and update that array
jl Update_First_Array
jmp Update_Second_Array
ret
};
Update_First_Array:
__asm
{
// min_elem = min (first elements of first array and second array)
// Put min_elem into the temp array
push dword ptr [EAX]
pop dword ptr [temp_arr + EDI * 4]
add EAX, 4
dec ECX
inc EDI
// Recursively call Merge on the updated array and the
// other array
call Merge
popad
ret
};
Update_Second_Array:
__asm
{
// min_elem = min (first elements of first array and second array)
// Put min_elem into the temp array
push dword ptr [EBX]
pop dword ptr [temp_arr + EDI * 4]
add EBX, 4
dec EDX
inc EDI
// Recursively call Merge on the updated array and the
// other array
call Merge
popad
ret
};
Merge_Copy_Back_Temp:
__asm
{
// Copy back the temp array into original array
// Arguments:
// EAX - original array address
// ECX - original array length
pushad
// For copying back, the destination array is EAX
mov EBX, EAX
// Now, the source array is temp_arr
mov EAX, temp_arr
call Copy_Array
popad
ret
};
First_Array_Over:
__asm
{
// Copy the rest of the second array to the temp arr
// because the first array is empty
pushad
mov EAX, EBX
mov ECX, EDX
mov EBX, temp_arr
imul EDI, 4
add EBX, EDI
call Copy_Array
popad
popad
ret
};
Second_Array_Over:
__asm
{
// Copy the rest of the first array to the temp arr
// because the second array is empty
pushad
mov EBX, temp_arr
imul EDI, 4
add EBX, EDI
call Copy_Array
popad
popad
ret
};
Copy_Array:
__asm
{
// Copy array to destination array
// EAX - Array start
// EBX - Destination array
// ECX - Array length
// Trivial case
cmp ECX, 0
jz Copy_Empty_Array
push ECX
sub EDI, EDI
};
copy_loop:
__asm
{
// Copy each element
push dword ptr [EAX + EDI * 4]
pop dword ptr [EBX + EDI * 4]
inc EDI
loop copy_loop
pop ECX
ret
};
Copy_Empty_Array:
__asm
{
ret
};
Read_Arr:
__asm
{
// EAX - array start
// ECX - array length
mov ESI, arr
sub EDI, EDI
};
loop1:
__asm
{
// Read each element
lea eax,[esi+edx*4]
inc EDI
loop loop1
ret
};
return 0;
}
I dare to disbelieve about the debugger opening during compilation. That said, this code
Merge_Sort:
__asm
{
// EAX - Array start
// ECX - array length
// Merge_Sort (first half)
// Length of the first half
// ECX /= 2
push ECX
shr ECX, 2
call Merge_Sort
has to overflow the stack when running: pushing ECX, shifting ECX, calling itself.
Short of installing the compiler myself, I suggest that you work through the code by adding #if 0 / #endif around a bunch of the code and seeing if you can figure out which instruction(s) the compiler is upset about - it clearly is the compiler crashing, which isn't a very good thing, but does happen.
Of course, that's after you have googled for the error message, etc... ;)
This is C++ using x86 inline assembly [Intel syntax]
Function:
DWORD *Call ( size_t lArgs, ... ){
DWORD *_ret = new DWORD[lArgs];
__asm {
xor edx, edx
xor esi, esi
xor edi, edi
inc edx
start:
cmp edx, lArgs
je end
push eax
push edx
push esi
mov esi, 0x04
imul esi, edx
mov ecx, esi
add ecx, _ret
push ecx
call dword ptr[ebp+esi] //Doesn't return to the next instruction, returns to the caller of the parent function.
pop ecx
mov [ecx], eax
pop eax
pop edx
pop esi
inc edx
jmp start
end:
mov eax, _ret
ret
}
}
The purpose of this function is to call multiple functions/addresses without calling them individually.
Why I'm having you debug it?
I have to start school for the day, and I need to have it done by evening.
Thanks alot, iDomo
Thank you for a complete compile-able example, it makes solving problems much easier.
According to your Call function signature, when the stack frame is set up, the lArgs is at ebp+8 , and the pointers start at ebp+C. And you have a few other issues. Here's a corrected version with some push/pop optimizations and cleanup, tested on MSVC 2010 (16.00.40219.01) :
DWORD *Call ( size_t lArgs, ... ) {
DWORD *_ret = new DWORD[lArgs];
__asm {
xor edx, edx
xor esi, esi
xor edi, edi
inc edx
push esi
start:
cmp edx, lArgs
; since you started counting at 1 instead of 0
; you need to stop *after* reaching lArgs
ja end
push edx
; you're trying to call [ebp+0xC+edx*4-4]
; a simpler way of expressing that - 4*edx + 8
; (4*edx is the same as edx << 2)
mov esi, edx
shl esi, 2
add esi, 0x8
call dword ptr[ebp+esi]
; and here you want to write the return value
; (which, btw, your printfs don't produce, so you'll get garbage)
; into _ret[edx*4-4] , which equals ret[esi - 0xC]
add esi, _ret
sub esi, 0xC
mov [esi], eax
pop edx
inc edx
jmp start
end:
pop esi
mov eax, _ret
; ret ; let the compiler clean up, because it created a stack frame and allocated space for the _ret pointer
}
}
And don't forget to delete[] the memory returned from this function after you're done.
I notice that, before calling, you push EAX, EDX, ESI, ECX (in order), but don't pop in the reverse order after returning. If the first CALL returns properly, but subsequent ones don't, that could be the issue.