News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

a snippet about dll

Started by Eric4ever, March 22, 2006, 03:44:04 AM

Previous topic - Next topic

Eric4ever

The example code is written in CBuilder,but I cannot make it in masm,please help me!
The .cpp is:
//---------------------------------------------------------------------------
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
char* (__stdcall *GetNumber)(int, char*);
int (__stdcall *GetSize)(int, char*);
HINSTANCE DllInst = NULL;
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{
  char* Code = "012345678910";
  int i;
 
  i = edt->Text.ToInt();

  if (DllInst == NULL) DllInst = LoadLibrary("Get.dll");
  if (DllInst)
  {
    GetNumber = (char* (__stdcall*)(int, char*))GetProcAddress(DllInst,"GetNumber");
    GetSize = (int (__stdcall*)(int, char*))GetProcAddress(DllInst,"GetSize");

    //Call GetNumber
    Edit1->Text = GetNumber(i, Code);

    //Call GetSize
    Edit2->Text = GetSize(i, Code);   
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
  Close();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
  if ( DllInst ) FreeLibrary (DllInst);
}
//---------------------------------------------------------------------------



How can I change it to MASM format, I cannot make the "GetNumber = (char* (__stdcall*)(int, char*))GetProcAddress(DllInst,"GetNumber");" and "Edit1->Text = GetNumber(i, Code);" clear.

zooba

Go through and write out what it's doing. Then do each thing in MASM.

Don't try and convert C++ code directly to assembly - it'll be far less efficient and probably harder then writing the code from scratch.

hutch--

Eric,

Zooba is right, just recode it, its quicker. Here is a quick example.


    GetNumber = (char* (__stdcall*)(int, char*))GetProcAddress(DllInst,"GetNumber");
    GetSize = (int (__stdcall*)(int, char*))GetProcAddress(DllInst,"GetSize");

  ; manual code

    LOCAL GetNumber :DWORD
    LOCAL GetSize   :DWORD

    .data
      pGetNumber db "GetNumber",0
      pGetSize   db "GetSize",0
    .code

    invoke GetProcAddress,DllInstance,ADDR pGetNumber
    mov GetNumber, eax

    invoke GetProcAddress,DllInstance,ADDR pGetSize
    mov GetSize, eax

  ; masm32 macro code

    LOCAL GetNumber :DWORD
    LOCAL GetSize   :DWORD

    mov GetNumber, rv(GetProcAddress,DllInstance,"GetNumber")
    mov GetSize,   rv(GetProcAddress,DllInstance,"GetSize")
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Eric4ever

Quote from: hutch-- on March 22, 2006, 04:24:24 AM
Eric,

Zooba is right, just recode it, its quicker. Here is a quick example.


    GetNumber = (char* (__stdcall*)(int, char*))GetProcAddress(DllInst,"GetNumber");
    GetSize = (int (__stdcall*)(int, char*))GetProcAddress(DllInst,"GetSize");

  ; manual code

    LOCAL GetNumber :DWORD
    LOCAL GetSize   :DWORD

    .data
      pGetNumber db "GetNumber",0
      pGetSize   db "GetSize",0
    .code

    invoke GetProcAddress,DllInstance,ADDR pGetNumber
    mov GetNumber, eax

    invoke GetProcAddress,DllInstance,ADDR pGetSize
    mov GetSize, eax

  ; masm32 macro code

    LOCAL GetNumber :DWORD
    LOCAL GetSize   :DWORD

    mov GetNumber, rv(GetProcAddress,DllInstance,"GetNumber")
    mov GetSize,   rv(GetProcAddress,DllInstance,"GetSize")


Thanks zooba and hutch!
I suppose translate is the the first step of recode :red , I just want to learn the approach of how to load and use the dll.
There is still a problem for me! I knew the "GetNumber = (char* (__stdcall*)(int, char*))GetProcAddress(DllInst,"GetNumber");" can be recode to:
invoke GetProcAddress,DllInstance,ADDR pGetNumber
mov GetNumber, eax

But the "Edit1->Text = GetNumber(i, Code);" made me puzzled. Can I recode it to:
invoke GetNumber,i,ADDR Code
mov Text, eax
invoke SetDlgItemText,hWnd,IDC_Edit1,addr GetNumber

GetNumber is just a DWORD variable...so...

PBrennick

If GetNumber is just a DWORD variable, why are you calling it as a procedure two lines earlier?

invoke GetNumber,i,ADDR Code ; Getnumber is a procedure, here
mov Text, eax
invoke SetDlgItemText,hWnd,IDC_Edit1,addr GetNumber ;GetNumber is a DWORD variable, here


This cannot be done.
Paul
The GeneSys Project is available from:
The Repository or My crappy website

Eric4ever

Quote from: PBrennick on March 22, 2006, 05:28:03 PM
If GetNumber is just a DWORD variable, why are you calling it as a procedure two lines earlier?

invoke GetNumber,i,ADDR Code ; Getnumber is a procedure, here
mov Text, eax
invoke SetDlgItemText,hWnd,IDC_Edit1,addr GetNumber ;GetNumber is a DWORD variable, here


This cannot be done.
Paul


Yes, that's why I'm confused.
How can I recode the  "Edit1->Text = GetNumber(i, Code);" sentence?

evlncrn8

at a guess, its going to set edit1 (editbox?) text value to the result from the call.. most likely doing a wsprintfa or something to convert the data

Eric4ever

Yes, But...

GetNumber = (char* (__stdcall*)(int, char*))GetProcAddress(DllInst,"GetNumber");

Edit1->Text =[b] GetNumber(i, Code);[/b]


Who can explain the bold for me, ThX.

zooba

A function names 'GetNumber' is called with parameters 'i' and 'Code', and the return value is copied to Edit1->Text.

Now, depending on what Edit1->Text is, this could be very complicated or very simple...

Eric4ever

Quote from: zooba on March 24, 2006, 08:06:15 AM
A function names 'GetNumber' is called with parameters 'i' and 'Code', and the return value is copied to Edit1->Text.

Now, depending on what Edit1->Text is, this could be very complicated or very simple...

I do it but it the sentence "invoke   GetNumber,i,addr Code" tells error:  error A2190: INVOKE requires prototype for procedure

The code I write is:

    .data?
hDllInstance              dd ?
i                                            dd                ?
GetNumber                             dd ?
GetSize                                   dd ?
    .data
szDll                                      db    'Get.dll',0
    .const
Code                 db '000000000000',0
pGetNumber db 'GetNumber',0
pGetSize db 'GetSize',0

invoke        GetDlgItemInt,hWnd,IDC_NUM,NULL,FALSE
mov           i,eax
invoke        LoadLibrary,addr szDll
.if              eax
mov           hDllInstance,eax
invoke        GetProcAddress,hDllInstance,addr pGetNumber
mov           GetNumber,eax
invoke        GetProcAddress,hDllInstance,addr pGetSize
mov           GetSize,eax

invoke        GetNumber,i,addr Code
invoke        SetDlgItemText,hWnd,IDC_Edit1,addr GetNumber
invoke        GetSize,i,addr Code
invoke        SetDlgItemInt,hWnd,IDC_Edit2,GetSize,FALSE


Where did I make mistake? ThX.

Mark Jones

Quote from: Eric4ever on March 24, 2006, 10:17:11 AM
I do it but it the sentence "invoke GetNumber,i,addr Code" tells error:  error A2190: INVOKE requires prototype for procedure

Hi Eric. A procedure is simply a type-defined function. It is used like this:


ProcedureName PROC <USES ESI EDI etc> <var1:DWORD, var2:DWORD, etc...>
    <assembler commands...>
    RET
ProcedureName ENDP


A procedure prototype defines the procedure. It is used as:


ProcedureName PROTO <:DWORD, :DWORD, etc...>


So to make a functional procedure, you have to do something like this:


; my App v1.0

myFunction PROTO :DWORD, :DWORD

.data
    szText    DB  "Hi there!",0
    szTitle   DB  "My Message",0

.code
start:
    invoke myFunction,addr szText,addr szTitle
    invoke ExitProcess,0

myFunction PROC text:DWORD,title:DWORD
    invoke MessageBox,0,text,title,MB_OK
    ret
myFunction ENDP

end start
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

Eric4ever

Thank you Mark.

I tried many times but there always has an error,I use "push Code" the error happens:
push Code     ; error A2070: invalid instruction operands
The Code defined in the .const
Code   db '000000000000',0    ; It's a character string which has 12 bytes 

And I tried "push offset Code", it link well but run error!

Here is my code:
  .data?
DllInstance   dd ?
i             dd ?
GetNumber     dd ?
GetSize       dd ?
  .data
szDll        db "Get.dll",0 
szVerbOpen   db "open",0
  .const
szError   db 'Get.dll Missing!',0
Code      db '000000000000',0         
pGetNumber  db 'GetNumber',0
pGetSize   db 'GetSize',0

   invoke GetDlgItemInt,hWnd,IDC_NUM,NULL,FALSE      ; IDC_NUM is a EDITTEXT
   mov i,eax 
   invoke LoadLibrary,addr szDll
   .if eax
    mov DllInstance,eax
    invoke GetProcAddress,DllInstance,addr pGetNumber
    mov GetNumber,eax
    invoke GetProcAddress,DllInstance,addr pGetSize
    mov GetSize,eax
   .else
    invoke MessageBox,hWnd,addr szError,NULL,MB_OK or MB_ICONWARNING
   .endif

    push offset Code
    push i
    call dword ptr [GetNumber]
    invoke SetDlgItemText,hWnd,IDC_Edit,addr GetNumber    ; IDC_Edit is a EDITTEXT(display the result)
...


THX.


Mark Jones

#12
Quote from: Eric4ever on March 28, 2006, 01:38:28 AM
I tried many times but there always has an error,I use "push Code" the error happens:
push Code     ; error A2070: invalid instruction operands
The Code defined in the .const
Code   db '000000000000',0    ; It's a character string which has 12 bytes 

And I tried "push offset Code", it link well but run error!

Hi Eric. Here "Code" is a label for your 12 bytes. PUSH can only accept WORDs and DWORDs as Register and Memory arguments, so pushing BYTEs is not allowed. "Push offset Code" works because the offset of Code is a DWORD, which can be pushed. To make this a little more confusing, you CAN push any immediate value (including a byte) but all immediates are pushed as DWORDs. Here are most of the legal ways the push command can be used:


.data
    three    DD 3   ; DWORD
    two      DW 2   ; WORD
    one      DB 1   ; BYTE

.code
    push EAX     ; eax is a DWORD, ESP-4
    push AX      ; ax is a WORD, ESP-2!
    push AL      ; this is not allowed!

    push three   ; dwords are ok, ESP-4
    push two     ; so are words, ESP-2
    push one     ; BYTEs cannot be pushed this way!

    push 12345678h  ; this is a DWORD, "12345678h" is pushed, ESP-4
    push 1234h      ; this is a WORD, "00001234h" is pushed, ESP-4
    push 12h        ; this IS acceptable, "00000012h" is pushed, ESP-4

    push OFFSET three  ; ok, the DWORD address of "three" is pushed, ESP-4
    push OFFSET two    ; ditto, ESP-4
    push OFFSET one    ; ditto, ESP-4
    push [EAX+ECX]     ; this adds EAX+ECX as DWORD offset, ESP-4


Pushing immediate values of any size is allowed simply because the value is zero-extended and stored as a DWORD. If you "push 13" then "0000000Dh" gets written to the current ESP.

ESP is the 32-bit stack pointer. It points to the current stack offset. If you push a DWORD to the stack, it is stored at ESP and then ESP decrements by 4, so the next value can be entered. Pushing WORD values decrements ESP by 2, so two WORD pushes are required to make one DWORD entry.

You can access values from the stack by the ESP value. Take this for instance:


    push 11111111h
    push 12345678h
    mov EAX,DWORD PTR [ESP+0]  ; eax == "12345678h"
    mov EAX,DWORD PTR [ESP+4]  ; eax == "11111111h"

    mov EAX,22222222h
    movzx EAX,WORD PTR [ESP+0] ; eax == "00005678h"
    movzx EAX,WORD PTR [ESP+2] ; eax == "00001234h"
    mov EAX,22222222h
    mov AX,WORD PTR [ESP+0]    ; eax == "22225678h"
    mov AX,WORD PTR [ESP+2]    ; eax == "22221234h"
   
    mov EAX,DWORD PTR [ESP+0]  ; eax == "12345678h"
    mov EAX,DWORD PTR [ESP+1]  ; eax == "11123456h"
    mov EAX,DWORD PTR [ESP+2]  ; eax == "11111234h"
    mov EAX,DWORD PTR [ESP+3]  ; eax == "11111112h"


Hope that helps. :bg
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

Eric4ever

Quote from: Mark Jones on March 28, 2006, 07:00:31 PM

Hi Eric. Here "Code" is a label for your 12 bytes. PUSH can only accept WORDs and DWORDs as Register and Memory arguments, so pushing BYTEs is not allowed. "Push offset Code" works because the offset of Code is a DWORD, which can be pushed. To make this a little more confusing, you CAN push any immediate value. Here are most of the legal ways the push command can be used:

----snip----

Hope that helps. :bg

Hi Mark,

Thanks for your kindly help and explanation  :U
I got it :green

Regards,
Eric