Multiline Ultimate Assembler (an x64dbg plugin)

Multiline Ultimate Assembler is a multiline (and ultimate) assembler (and disassembler) plugin for x64dbg and OllyDbg. It’s a perfect tool for modifying and extending a compiled executable functionality, writing code caves, etc.

Source code:
https://github.com/m417z/Multiline-Ultimate-Assembler

rar multiasm.rar (475.86 kB, changelog)

Posted in Releases, Software by Michael (Ramen Software) on September 13th, 2009.
Tags: , ,

219 Responses to “Multiline Ultimate Assembler (an x64dbg plugin)”

  1. Ange says:

    i really like that plugin, but sometimes for no reason, it doesn’t want to accept strings – the example like on this page wouldn’t work, it would give me a ‘command mnemonic expected’ in the middle of “hello world” string.

  2. Ange says:

    just ignore previous comment, i didn’t see i don’t have the latest version 🙂

  3. totalgame says:

    How do i plugin on ollydbg? I’ve put the plugin in plugin folder but it doesn’t appear on olly. Should i set something on ollydbg.ini? -Thnx- nice blog

  4. Joe McKenzie says:

    AWESOME!! This plugin would’ve saved me a lot of time on multiple occasions.

  5. Morten says:

    Very useful. But it crashes almost everytime.

    It writes the opcodes just fine, but then crashes Olly a few seconds later.

    • Morten says:

      Okay, I’ve pinpointed it to Labels.

      If “Write Labels” is enabled in options, it crashes me Ollydbg (1.10 – Tried clean install too).

      If I untick “Write Labels” it works just fine.

      • Morten says:

        PS: I can’t get it to support labels for loop instructions (LOOP, LOOPD, LOOPE).

        @Bla:
        LOOP @Bla ; does not work
        LOOP 00401000; works

      • I’ve never experienced such crashes. You say it happens with any code/binary even on a clean olly? Can you say on which RVA it crashes?

      • After a number of experiments, I was able to reproduce the issue. Seems like it’s a bug of Ollydbg and it’s Quickinsertname/Mergequicknames functions. Maybe Ollydbg does not expect these functions to be called from another thread – what MUltimate Assembler does.

        It does not crash on my PC while assembling a sane amount of code, but inserting labels/comments in a loop make it eventually crash.
        Perhaps your PC is faster, and thus it happens regularly for you.

        Disabling “Write Labels” and “Write Comments” will help, but if you find these useful, you could make MUltimate Assembler use Insertname instead of Quickinsertname/Mergequicknames (Insertname accepts the same parameters as Quickinsertname). As an Ollydbg user it should not be difficult for you 🙂 Try it and tell me how it works.

      • The crash was fixed in v1.3

  6. Updated to v1.2.1

    Bug fixes:
    – Now correctly assembles loop instructions with labels (reported by Morten).
    – Fixed assembling short jumps with labels on high addresses.

  7. Updated to v1.2.2, which only creates a single thread on startup and uses it instead of creating a new thread every time the assembler window is opened.
    That makes it work together with the phantOm plugin.

  8. MCKSys Argentina says:

    Great Plugin!!

    Thanks!

  9. MFan says:

    Thanks for the update. Disassembler is awesome! Still waiting for tab renaming feature, though. 🙂

  10. Apuromafo says:

    nice plugin as say MCKSys Argentina ,, i use from version 1,

    ask: is posible do this same for ollydbg 2 ( now was a update and cann add plugin ^^)

    BR, Apuromafo

  11. tuk says:

    this is my fav olly plugin, not to seem ungrateful but I think it will take some time for the plugin documentation to appear..and its a real pain having to juggle multiple versions of olly ..as v2.0 is the best now even tho a little buggy

    thanks for your work

  12. v1.7.1:
    * Search/replace in editor (hotkeys: Ctrl+F, Ctrl+H, F3, Shift+F3).
    * Fix: Correctly handle prefixed instructions (LOCK, REP, REPE/REPZ, REPNE/REPNZ).

  13. R4ndom says:

    Just came across your amazing plugin. It is a life-saver. I am doing a tutorial on code caves right now and I can’t wait to introduce your plugin to my many readers.

    I have one feature request. Seeing as a lot of the members on my site are beginners, it would be great if, instead of just giving a generic error, your plugin said what line number the error was on or highlight the line or something. I can already tell I’m going to get numerous questions like “Can you look at my code? It says I have a ___ error but I can’t figure out where”.

    Anyway, if you have the time. If not, it’s still an amazing plugin and I will use it often.

    I am also going to ask my minions to donate to your cause, as I plan to do as well. Too few people get recognized for their hard work.

    -R4ndom

  14. R4ndom says:

    btw: do you have any sort of manual or quick guide or anything? I would love to include something in the tutorial…

  15. VEG says:

    Может быть вам стоит рассказать об этой штуке на Хабрахабре? Там очень большая аудитория, и статьи на подобную тематику воспринимаются очень тепло. Пример: http://habrahabr.ru/post/51857/

    Также вы можете рассказать о 7TT, рассказав для примера как вы делали какую-нибудь простую функцию (чтобы не посчитали рекламой и воодушевить других программистов). Это будет просто бомба! 🙂 Ну и +10 к популярности вашего ПО. Для примера, моя последняя статья ( http://habrahabr.ru/post/168269/ ) за 10 часов уже собрала больше 25000 просмотров — а это немало.

    Страна должна знать своих героев! 🙂 Если надумаете что-нибудь написать и оценить Хабраэффект, я могу поделиться инвайтом.

    • Может быть, хотя не уверен, что из меня выйдет хороший писатель. Да и время для этого найти нужно.

      А вообще я с Хабром знаком, почитываю иногда.
      Про 7TT, кстати, кто-то уже писал (кратко, но все же):
      http://habrahabr.ru/links/125911/

      Ну а так, если надумаю писать, буду знать к кому обращаться за инвайтом. Спасибо за предложение 🙂

      • VEG says:

        Это не считается, поскольку заметка даже на главную не попала. Секрет успеха на хабре — немножко подробностей, как оно работает. А там где вы показали кроме ссылки ничего нет.

        Что касается написания статей. Нужно просто написать пару первых предложений — остальное уже как-то само получается 🙂

    • Также вы можете рассказать о 7TT, рассказав для примера как вы делали какую-нибудь простую функцию

      Вот, накатал статейку:
      Здесь была ссылка

      Ваше мнение?

  16. Mr. eXoDia says:

    Hi,

    Would it be possible to also compile this plugin as a standalone DLL/static library? This would help with writing tools that need to inject code for example.

    Please consider it.

    Greetings,

    Mr. eXoDia

    • Hi Mr. eXoDia,

      The plugin uses OllyDbg’s assembling and disassembling API, so it can’t be made standalone. Have you considered using FASM or similar?

      RaMMicHaeL.

      • Mr. eXoDia says:

        Thanks for the reply! Yes I considered fasm, but your plugin just rocks..

        And does your plugin only rely on this library or also on other parts of olly (only a dll that assembles is good enough) because disasm is open source: http://ollydbg.de/srcdescr.htm

        Greetings

        • Here are the functions it imports from Olly:
          Addtolist
          Pluginreadstringfromini
          Findmemory
          Findmodule
          Finddecode
          Pluginreadintfromini
          Readmemory
          Disasm
          Assemble
          Dumpbackup
          Plugingetvalue
          Getstatus
          Findsymbolicname
          Pluginwriteinttoini
          Writememory
          Quickinsertname
          Pluginwritestringtoini
          Mergequicknames
          Deletenamerange
          Findname

          So no, not much
          But it’s designed to assemble code to memory. You want a standalone library to write code to a file, right? If so, the division to sections (<401000> stuff) would either dropped, or I’d have to use a custom file format or something.

          In any case, how would that be better than FASM?
          In addition, FASM supports macros, which are very powerful and might come in handy.

          P.S.

          your plugin just rocks..

          Thanks 🙂

          • Mr. eXoDia says:

            the sections () would not be used with my code.. It’s more like this:

            unsigned int makeinline(unsigned char* result, char* assembly, unsigned int va_base)

            result is the resulting assembly code
            assembly is just the plain text code (with @label, “\x03” support)
            va_base is the virtual address where the result will be written later on

            return value is the length of the resulting buffer.

            For me it’s more about the simple syntax and compatibility with the odbg version of multimate assembler.

            Something optional would be that the function also returns a relocation table, but for me it’s mainly about the code style.

            Greetings

            • Let’s make a deal 🙂

              I make the standalone library you requested, and you write an article about how you use it, what it’s good for, etc.
              I’ll post your article on my blog, so others can see what it’s all about, and maybe use it too.

              What do you think?

  17. Mr. eXoDia says:

    Deal 🙂

  18. Morten says:

    Hello again.

    I’ve been trying to get it to work with ollydbg 2. I’ve downloaded the latest version and placed multiasm_odbg2.dll in ollydbg2\Plugins, and set up the plugin directory in the ollydbg options.

    However, the Plugins menu is grayed out, and the plugin doesn’t seem to load at all.

    Reading on ollydbg2.de it seems he changed the plugin interface, so I guess it’s incompatible with the new version.

    Any chance of an update for the latest version of ollydbg2?

    Thanks.

    • Morten says:

      Hmm, downloaded the second latest version of olly, and now it works. Guess I’ll just stick with that one for now.

    • Hi,

      The latest version, v2.1.1, is compatible with the latest version of OllyDbg, odbg201h.zip (November 19, 2012). Just rechecked it.
      Could it be that you’re trying an older version of the plugin?

      • Morten says:

        Hmm. Weird. It works now. I redownloaded olly 201h and MUA v2.1.1 from the top of the page.

        Though I’m certain that it’s the same versions I used before. Perhaps it’s some ollydbg settings. I’ll poke around.

        Thanks.

  19. Mr. eXoDia says:

    Hey,

    I’ve been busy with this standalone library, but currently real life stuff is eating all my time… I’ll continue writing the tutorial, but it might take more time.

    Greetings

  20. Mr. eXoDia says:

    Hey,

    So I had some time to ‘finish’ this coding example of your library so here it is: http://rghost.net/private/45983365/f6fdd54ba9db02e63867bf1fe66ab2c7 I still need to write a full tutorial in PDF format, but here is just what I could do by now (it works, tested on one target, but it works)

    Greetings,

    Mr. eXoDia

    • Nice 🙂

      The technique mostly targets protectors, right?

      I found a bug that caused it to crash on my PC, pefunc.cpp line 70:
      psh=(IMAGE_SECTION_HEADER*)(&pnth->OptionalHeader)+pnth->FileHeader.SizeOfOptionalHeader;

      The pointer is not calculated correctly.

      Also, it might be worth creating the extra section automatically.

      • Mr. eXoDia says:

        Yes I think mostly for targeting protectors. But it could also be useful if someone wants to make a small disassembler with easy multiline assembling feature (although x64 would be better in that case).

        Thanks, I reused the code from another project and it isn’t really used so I experienced no crashes. Fixing line:
        psh=(IMAGE_SECTION_HEADER*)((DWORD)(pnth)+pnth->FileHeader.SizeOfOptionalHeader+sizeof(IMAGE_FILE_HEADER)+sizeof(DWORD));

        I will see if I’m going to implement this feature.. usually I use titanengine, but in this case I would need to write this code by myself (no problem, but it takes time).

        Greetings,

        Mr. eXoDia

  21. Mr. eXoDia says:

    Hi,

    Lately I was using multimate asm to do some relative coding in DLLs, but would it be possible to add a syntax for the module that you’re currently debugging?

    Greetings

  22. adoxa says:

    After using this plugin for a while to patch a program, I’ve noticed some things.

    Some sort of align directive would be useful, allowing jump tables or floating point constants to automatically go to dword boundaries.

    Some sort of “stop” directive might be nice, too. Something like:

    some instructions
    !stop ; if you get here, there’s too many instructions

    The editor doesn’t like undoing in overwrite mode. For example, type in “ab”, turn on overwrite, go back and delete the “a”, undo and “a” replaces “b”.

    A keyboard shortcut (Ctrl+D perhaps) to put the debugger back into focus would be really nice.

    • Thanks for the feedback.

      Some sort of align directive would be useful, allowing jump tables or floating point constants to automatically go to dword boundaries.

      I guess it can be useful sometimes, but It will complicate the syntax, and I’m not sure it’s worth it.

      I remember somebody suggested a “bp” pseudo instruction, which will put a breakpoint on the following command. Perhaps something similar to C’s “pragma” directive is worth considering.

      !stop ; if you get here, there’s too many instructions

      How will it know when there are too many instructions?
      It might work like this, maybe:
      !max_address(00401020)
      I think it might be a candidate for a pragma-like directive as well.

      The editor doesn’t like undoing in overwrite mode. For example, type in “ab”, turn on overwrite, go back and delete the “a”, undo and “a” replaces “b”.

      I’m not the author of the editor component. I’m using RAEdit. You’re welcome to fix this and send me a pull request:
      https://github.com/RaMMicHaeL/SimEd

      A keyboard shortcut (Ctrl+D perhaps) to put the debugger back into focus would be really nice.

      That should be easy.

      • adoxa says:

        I guess it can be useful sometimes, but It will complicate the syntax, and I’m not sure it’s worth it.

        How about as an extension to the label format: @label@align: would create @label as a multiple of align bytes?

        How will it know when there are too many instructions?

        Yeah, sorry, my example didn’t format right and there was no edit; I’ll try again.
        <start>
        some instructions
        !stop

        So stop is an address, not the literal word.

        You’re welcome to fix this and send me a pull request

        Done.

    • adoxa says:

      How will it know when there are too many instructions?

      Since you use a tag-like format for the address, how about this:
      <start>
      instructions
      </stop>

    • I’ve just released v2.1.4, which fixes the editor bug (thanks for the fix!) and implements Ctrl+D.
      As for the other two suggestions: I’ll add them to my TODO list 🙂

      • adoxa says:

        Yeah, that key’s much better than having to click the mouse or double Alt+Tab. But the undo fix has introduced another problem: you’ve spelt my moniker backwards in the changelog. 🙂

        • Oops, sorry for that. It will be fixed in the next version, unless you want me to release one just with the moniker fix.

          About the align/stop suggestions, I thought about it some more, and here’s what I think:

          I don’t like your suggestion of including aligning in the label (@label@align:). Labels are just names, and IMO shouldn’t imply any data write/manipulation.

          Your suggestion of the stop address (</stop>) is nice, but I thought it would be better to generalize such extras into a pragma-like thing, like I mentioned earlier.

          Such commands could begin with ‘!’. Examples:

          <00401000>
          
          nop ; 00401000
          
          !align 4 ; Fills the three bytes with zeroes
          nop ; 00401004
          
          !align 4 FF ; Extra param, fills the three bytes with FF
          nop ; 00401008
          
          ; ...
          
          <00402000>
          
          nop ; 00402000
          
          !assert_addr_na 00402001 ; OK
          
          <00402000>
          
          nop ; 00402000
          nop ; 00402001
          
          !assert_addr_na 00402001 ; Error 
          

          I don’t really like the “assert_addr_na” (na – not above) name too much, but I couldn’t think of something both short and descriptive. Ideas are welcome 🙂

          • adoxa says:

            Oops, sorry for that. It will be fixed in the next version, unless you want me to release one just with the moniker fix.

            No, it can wait.

            I don’t like your suggestion of including aligning in the label (@label@align:). Labels are just names, and IMO shouldn’t imply any data write/manipulation.

            Fair enough, but it would have made dword-aligned strings much nicer to write.

            @str1@4: "string 1"
            @str2@4: "string 2"

            versus

            !align 4
            @str1: "string 1"
            !align 4
            @str2: "string 2"

            I don’t really like the “assert_addr_na” (na – not above) name too much, but I couldn’t think of something both short and descriptive.

            Would an expression work, making assert a bit more general?

            >402000>
            nop
            nop
            !assert addr <= 402001

            Something else that would be useful is an enhancement to anonymous labels, where each additional @ skips another label.

            je @@f ; jumps to second anonymous label
            ...
            jne @f ; jumps to first
            ...
            @@: ; jne goes here
            ...
            @@: ; je goes here

            • Fair enough, but it would have made dword-aligned strings much nicer to write.

              I think making !align 4 available, and making @label@4: a syntax sugar of it, with the note that it’s just a convenience and the two are not really related, is OK.

              Would an expression work, making assert a bit more general?

              I thought about it too, but first, it needs to be implemented. Second, is it needed at all?
              What else is there to assert about besides addr? And why would you use an operator other than “<=”?

              Something else that would be useful is an enhancement to anonymous labels, where each additional @ skips another label.

              Is it worth the complexity? Why not just use a named label?
              Is there an assembler which uses this syntax?

              • adoxa says:

                What else is there to assert about besides addr? And why would you use an operator other than “< =”?

                Okay, maybe approach it a little differently: !stop_at 402001 Ideally that would restore from where it started and tell you how far it went beyond the stop address (which is what it implies, whereas the assert just implies a warning and it’s up to you to find out how far it went and restore it).

                Is it worth the complexity?
                It would be for me. You could always make things simple for yourself and send me the source…

                Why not just use a named label?
                Because then I have to think of a name. And it’ll show up in OllyDbg.

                Is there an assembler which uses this syntax?
                I just saw it recently, but don’t remember where. It was done with macros, possibly with fasm.

                • adoxa says:

                  Yet another approach would be to turn the address into a range: <402000-402001>.

                • Okay, maybe approach it a little differently: !stop_at 402001

                  I don’t see how it’s different than !assert_addr_na, except the name. There’s no reason why the assert can’t show you an informative message, and move the caret to its location.
                  I don’t like the stop/stop_at names, as they are not descriptive. If you’d browse an asm source and see a “stop” command, I assume you’ll get confused.

                  You could always make things simple for yourself and send me the source…

                  Heh, I’ll keep that in mind 🙂

                  It was done with macros, possibly with fasm.

                  Well, macros are macros. Not all the things they allow you to do are useful.

                  • adoxa says:

                    I now like the range idea best, as that lets the assembler know ahead of time where it should stop. I’d say it’s also very similar to what you already do with the end-of-section, as I recently discovered.

                    If you really want to be descriptive, maybe it should be “Multiline not-as-Ultimate-as-all-that Assembler.” 😉

                    • You’re talking about this message, right?

                      End of code block exceeds end of memory block (2 extra bytes)

                      There’s nothing about “know[ing] ahead of time where it should stop” here. It just assembles the block, and then does the check. Otherwise, it wouldn’t be able to say how many extra bytes you have.

                      Perhaps the range syntax is indeed the better one, but I don’t like the fact that it uses ‘-‘, which could be interpreted as a minus. Perhaps it could look like this:
                      <00401FFE..00401FFF>

                      If you really want to be descriptive, maybe it should be “Multiline not-as-Ultimate-as-all-that Assembler.” 😉

                      It’s all relative. It’s not as flexible as e.g. FASM is, but it surely is ultimate comparing to what you have built in OllyDbg 🙂

                    • adoxa says:

                      Perhaps it could look like this:
                      <00401FFE..00401FFF>

                      That would be great.

    • Some sort of align directive would be useful, allowing jump tables or floating point constants to automatically go to dword boundaries.

      Some sort of “stop” directive might be nice, too. Something like:

      some instructions
      !stop ; if you get here, there’s too many instructions

      you’ve spelt my moniker backwards in the changelog.

      I’ve implemented/fixed those in v2.2.
      I did not do extensive testing, so please, try to feed the assembler with various invalid input and see whether it always works as expected. Tell me if it doesn’t. Thanks 🙂

      • adoxa says:

        Excellent, I’ll rearrange stuff again to take advantage of it and let you know how it goes. Now I can remove all those extra \0-s I’ve added to my strings (but to free up space in the code section, I’ve moved jump tables and float constants to padding at the end of .rdata, so with aligned strings everything else is already aligned).

      • adoxa says:

        It seems @label@align: still assigns the pre-aligned address to @label.

      • adoxa says:

        The range is working a treat, although I keep getting caught out. E.g. it says two bytes over, so I tweak it, but then it says three bytes over – argh, look where the cursor is!

        If I may make one more suggestion, perhaps recognise jmp @e (e for end) and if it doesn’t fit, just nop it instead.

        • E.g. it says two bytes over, so I tweak it, but then it says three bytes over – argh, look where the cursor is!

          I’m not sure I understand. Can you provide an example?

          If I may make one more suggestion, perhaps recognise jmp @e (e for end) and if it doesn’t fit, just nop it instead.

          What I think might be a better idea is filling the unused bytes of the block with NOPs.
          I need to think about a good syntax for it, though.

          • adoxa says:

            You place the cursor on the instruction that goes over, but I only look at that the second time. 🙂 So given pop esi/ret 4, you’d tell me it’s one byte over (and leave the cursor on the pop), I’ll save one byte and now it’s three bytes over (with the cursor on the ret 4, which now I notice.) That’s just my misunderstanding with how I want it to work and how it actually works.

            As for NOP‘ing blocks, how about !pad [90] – 90 being the NOP opcode by default, but could also allow 0CC, or 00 for data areas. Or maybe !fill.

        • Oh, so you just want @e to be a special label that refers to the address after the last command of the block, right? Seems like I’ve misunderstood your suggestion. It seemed to me like you’re suggesting some kind of special case command jmp @e, according to:

          and if it doesn’t fit, just nop it instead.

          I thought about another improvement, which may help here too, but is much more generic: implementing local labels. You could perfix the label with e.g. a dot, and it would apply only for the current block. For example:

          <00401000>
          
              jmp @.e ; jump below
              nop
          @.e:
          
          <00401010>
          
              jmp @.e ; jump below
              nop
          @.e:
          
          <00401020>
          
              push @.e ; error, label is not defined
          

          Perhaps a better syntax can be introduced. I have to think about it.

          • adoxa says:

            No, you were right the first time – ideally I want the label (so it can also be used with conditional jumps) and a NOPable jump (to continue from the end of the block).

            ; patched code is smaller than original
            <401000..401010>
                jmp @e ;; jmp 401010 - skip remainder
            
            ; patched code is one byte smaller than original
            <401100..401101>
                jmp @e ;; nop - all that's needed
            
            ; patched code is same size as original
            <401200..401200>
                jmp @e ;; nothing at all - already there
            

            Local labels would be good, too (but they wouldn’t help with the above, since that effectively wants to jump outside the block). My preference would be either @@local (MASM/TASM default) or, if feasible, just .local (NASM/FASM, which actually append to the previous global, so still accessible as @global.local, if you really want to be fancy).

  23. adoxa says:

    I’ve come across an “Internal error”. I was using unused .data for some variables, some of which I had initialized. I then remembered that that part of .data is really virtual, so I split it into two, placing the initialized stuff back in .text (as I’ll be writing it all back to the exe). To compensate I wanted to add the difference of the pointers: push [dword ecx+@textvar-@datavar]. It’ll do the +@textvar or the -@datavar, but not both (OllyDbg itself assembles it).

    • That’s an interesting issue, caused by a kind of a hack I use.
      Consider the following example:

      <00401000>
          jmp @next
          ; more code
      @next:
      

      When doing the first pass on the code, you see “jmp @next”, but you don’t yet know what @next is. It might result in a long jump or a short jump. But you have to know the length of the jmp command in bytes, in order to be able to calculate @next.

      What I do on the first pass is replacing any label with the address of the command plus INT_MAX. So “jmp @next” gets assembled as “jmp 80400FFF”, making it a long jump. Then I know it’s going to be 5 bytes long, and I can proceed to the next commands.

      On the second pass, when I know what @next is, I can assemble the real jmp command, which will always be long, whatever @next is.

      With your code, gets assembled in the first pass as:
      push [dword ecx+(addr+INT_MAX)-(addr+INT_MAX)]
      Which results in:
      push [dword ecx+0]
      The zero is discarded and the command length becomes smaller than it needs to be. That’s why there’s an error on the second pass.

      There are other possible issues with this hack technique, for example:

      <80000001>
          PUSH @a
      
      <00401000>
      @a:
      

      But the code range of 80000000 +- FF is rare enough that nobody has noticed.

      I need to think about it. One solution can be to replace every constant which is set by a label with a literal which fits only in a DWORD, -and- the difference between it and the current address also fits only in a DWORD. I don’t think OllyDbg is flexible enough to handle it.

      Ideas are welcome 🙂

      • adoxa says:

        I had a look at how Playtime handles it and it turns out it doesn’t – not only does it barf when you give it two labels, a single label is generated incorrectly.

        In my case, performing the substitution on the first pass would be sufficient (@datavar is defined before the push). Otherwise, maybe you could use a variable to store the offset, then reset it once it’s been used.

        int label_offset = INT_MAX;
        // …
        if (label) {
        offset = addr + label_offset;
        label_offset = 0;
        }

        The other option is to ask Olly to use (rather than ignore) the LARGE keyword to actually assemble the long form.

        • I had a look at how Playtime handles it and it turns out it doesn’t – not only does it barf when you give it two labels, a single label is generated incorrectly.

          Do you mean this?
          http://code.google.com/p/ollydbg2-playtime/

          I’m not familiar with it (and I don’t really know Lua). What relevant functionality does it have?

          In my case, performing the substitution on the first pass would be sufficient (@datavar is defined before the push).

          Yeah, but it must not be the case. The two labels could be defined below.

          maybe you could use a variable to store the offset, then reset it once it’s been used.

          Do you mean for every command?
          If I understand your suggestion correctly, this:
          mov dword [@L1], @L2
          will turn to this:
          mov dword [(addr+INT_MAX)], (addr)

          which might result in a short form. Also, you can still get a case where it fails, e.g.:
          mov dword [(INT_MAX+addr_of_L1)-@L1], 1

          With this approach, it’s all about probability.

          The other option is to ask Olly to use (rather than ignore) the LARGE keyword to actually assemble the long form.

          I’m not sure it has such a feature. Also, how could I get the difference between e.g.:
          mov dword @L1, 401000
          and:
          mov dword [401000], @L1

          Meanwhile, try this one:
          https://www.dropbox.com/s/ddpvvrmmndf9vzi/multiasm_v2.2.3.2.rar?dl=1
          It has some improvement to the hackfix. Not perfect, but should work for your case.

          • adoxa says:

            I’m not familiar with it (and I don’t really know Lua). What relevant functionality does it have?

            I’m not all that familiar with it either (nor do I really know Lua); I just knew it had an assembler, with labels, so I tried it out to see what would happen.

            If I understand your suggestion correctly, this:
            mov dword [@L1], @L2
            will turn to this:
            mov dword [(addr+INT_MAX)], (addr)

            Well, that depends where you put the initializer. 🙂 But then, isn’t that okay anyway? No one’s going to generate code between -80..7F, so just using addr itself should be fine.

            Also, you can still get a case where it fails, e.g.:
            mov dword [(INT_MAX+addr_of_L1)-@L1], 1

            I don’t follow what you’re trying to say. If you already know the address of L1, why are you still adding INT_MAX? And @L1-@L1 really should be zero, anyway.

            Meanwhile, try this one. It has some improvement to the hackfix. Not perfect, but should work for your case.

            Indeed it does, thank you.

            • But then, isn’t that okay anyway? No one’s going to generate code between -80..7F, so just using addr itself should be fine.

              Yes, unless the command interprets the literal as a relative address. I’m not familiar with a command which contains two literals, and one/both of them is relative, but maybe there is one.

              I don’t follow what you’re trying to say. If you already know the address of L1, why are you still adding INT_MAX? And @L1-@L1 really should be zero, anyway.

              I meant the address of the command, not of @L1. Say, if the address of the command is 400000, and you write [803FFFFF-@L1], it will become zero on the first pass, and non-zero on the second pass. The point is, whatever delta I choose, there’s always a range which will result in an error. To fix it properly, I’ll need to actually parse the command and understand the role of the labeled constants.

              Indeed it does, thank you.

              Great. This one just adds extra 0x11111111 to every label.

  24. adoxa says:

    If you were at all curious, here is what I was working on. (As it turns out, I rearranged stuff again, so ended up not using !pad; could have used @e, though.)

    • Yes, I was curious, and in fact I was about to ask you 🙂

      The amount of code looks impressive. Seems like you’ve put quite a bit of effort into it. I did something similar with Resouce Hacker here.

      Have you considered writing an article about it? I’ll happily publish it on my blog, if you’d like.

      could have used @e, though.

      What makes it more useful than !pad? It also turns into a nop if the jump command doesn’t fit.

      • adoxa says:

        I did something similar with Resouce Hacker here.

        That reminds me…

        Have you considered writing an article about it?

        It’s bad enough writing a doc, I don’t wanna be writing more.

        What makes it more useful than !pad?

        @e just avoids having to type in the end address again. 🙂 It depends how you want to use it, I guess. There were only two places where I thought the patched code might be about the same size (one was one byte smaller, the other exact length; but both these cases ended up becoming redundant and I just changed a pointer, instead); every other place I was pretty sure was going to be smaller, so jumping out was assumed and padding was not necessary. BTW, adding the end address to the disassembler might be nice (perhaps as an option).

  25. Valentin says:

    На протяжении длительного времени я использую в работе этот прекрасный инструмент. Но обратил внимание на следующее. Первые несколько запусков плагин работает очень быстро, а затем начинает тормозить (начинает медленно открывать окно, долго выполняет захват выделенного кода, и т.д.). Такое ощущение, что он начинает (после нескольких запусков) усиленно поедать ресурсы, и, при этом тормозит не только сам плагин, но и отладчик OllyDbg. Приходится перезапускать отладчик, после чего плагин опять начинает быстро работать. Нельзя ли предусмотреть принудительную очистку памяти после закрытия плагина?

    • Ни разу не сталкивался с подобной проблемой.
      Есть признаки кроме тормозов? Память, CPU?
      Почему Вы решили, что проблема в Multiline Ultimate Assembler, а не в другом плагине, например?

      • adoxa says:

        I had a similar problem. Initially, it would assemble instantly (well, that’s how I remembered it, anyway). I then exited, deleted OllyMoreMenu 1.5 (I never used it and it interfered with Ctrl+O), restarted and it would take 19 seconds to assemble. I couldn’t put OllyMoreMenu back on, as I didn’t have a backup and couldn’t find it again, only 1.5+, which instantly crashed. It somehow resolved itself and now takes about 3 seconds to assemble (the somewhat bigger final version), although sometimes it was about 10 seconds (possibly with a “Not responding” message). Testing just now takes about 6 seconds.

        • The amount of time it takes to assemble is not the same issue as interface sluggishness (delay upon opening a window, upon disassembling, etc., which is what Valentin reports). Of course, this issue is not less important. I’ve never felt that it’s too slow, but on the other hand, I’ve never worked with files as large as e.g. your 2000-liner. I’ll experiment with large files and will see what causes the delay.

        • I took a look at it. On that occasion, I’ve got rid of an ugly hack: the plugin created a new thread for the GUI, mainly in order to call TranslateAccelerator and IsDialogMessage. That caused glitches and performance issues here and there, and could cause data races, as OllyDbg doesn’t guarantee thread safety for it’s API. In order to move the assembler to Olly’s thread, I had to use another hack, a small WinAPI hook, but I believe that it’s worth it.

          As for performance: I did a couple of quick tests, using your FLStat.asm as a target, and here are the timing results on my PC with OllyDbg 2:
          6515 ms. – overall assembling time with v2.2.4.

          3579 ms. – overall assembling time with v2.2.5, out of which:
          – 2469 ms. – assembling instructions using OllyDbg’s Assemble/Assembleallforms functions.
          – 1094 ms. – writing memory using OllyDbg’s Writememory + Removeanalysis.

          So as you can see, the bottlenecks now are OllyDbg’s functions, especially the assembler.

    • Попробуйте, пожалуйста, версию 2.2.5.

  26. adoxa says:

    Another thing that might be nice to have is the ability to split regions. For example, adding entries to jump tables, putting the new tables in unused space in .rdata.

    <401000> jmp dword[eax*4+@table1]
    <rdata=402000> ;; create an alias for this region
    @table1:
        dd @addr1_0
        dd @addr1_1
    
    <401100> jmp dword[eax*4+@table2]
    <rdata>    ;; continue where it left off
    @table2:   ;; so this is at 402008
        dd @addr2_0
        dd @addr2_1
    

    That allows keeping related code & data together in the editor, even though they’re separate in memory.

  27. Kindly says:

    Здаров! Тут такая трабла с последней версией плага, на Win 7×64 ru вываливается с ошибкой:
    —————————
    Multiline Ultimate Assembler error
    —————————
    Couldn’t find the TranslateMDISysAccel function in User32.dll
    —————————
    ОК
    —————————
    функция присутствует. версия библы: 6.1.7601.17514 (win7sp1_rtm.101119-1850)

    у коллеги версия такая же винды, но версия библы: 6.1.7600.16384, и у него все запускается нормально.

    предыдущие версии плагина запускаются нормально, проблема только в последнем билде. плиз пофиксь по возможности.

    • Здравствуй!

      Не получилось воспроизвести. OllyDbg 1 или 2? Оригинальный? Другие плагины есть, без них работает?

      • Kindly says:

        пробовал на чистом оригинальном 1. на данный момент нет технической возможности обсудить данный вопрос подробнее. как только будет время и возможность, предоставлю все необходимое для попытки устранения данной несовместимости.

      • Kindly says:

        Все ок, была виновата сборка NiceDbg от SLV/ICU. До того, как посмотрел в эбаут, думал, что это оригинал)
        Если возможно, пофикси горизонтальный скролл. Когда я добавляю большой массив байтов, то скролл не захватывает всю длину массива.

        • сборка NiceDbg от SLV/ICU

          Можно ссылку? Интересно, что там происходит. Или приват? 🙂

          Если возможно, пофикси горизонтальный скролл.

          Как это можно воспроизвести?
          В целом, плагин использует компонент RAEdit, исходники которого можно найти здесь (и отправить пулл реквест):
          https://github.com/RaMMicHaeL/SimEd/tree/master/RAEdit

  28. Kindly says:

    Вот сборка + скрин скролло
    rghost.ru/57884230

    • Плагин не работает со сборкой потому, что Оля сжата, и в таблице импортов нету функции TranslateMDISysAccel, которую плагин хукает. Я это исправил, фикс будет доступен в следующей версии, но если надо, могу выложить сейчас.
      Насчет горизонтального скролла – похоже, эта фича просто не реализована. Так как компонент не мой, и так как мне это особо не мешает, исправлять пока не планирую.

      • Kindly says:

        Спасибо! Пересел таки пока на другую сборку)) А скролл не критично, просто в глаза бросилось. Отдельный респект за релиз для x64dbg!

  29. tom says:

    I really like this plugin, but this plugin when writing the annotation does not support Chinese string, Chinese character display garbled.

  30. danrevella says:

    Hi!
    In my opinion Multiline assembler is the best plugin ever released for Ollydbg.
    Many time I have renonced to patch a program coz when the patching job was a bit complicate, it was near to impossible follow the flux of the patched code…
    BTW………
    Do you thing in future will be possible to get a search and replace function in Multilne assembler?
    Many thanks!!

    dan

  31. Thank you for the awesome plugin!

    It seems the editor doesn’t really support non-ASCII characters, so for the time being I have to use unicode code points. You’re probably already aware of this, but if not, you can see this in the image below.

    http://puu.sh/cTyy2/57c9829598.png

    It’s not a huge issue or anything, it still works, but there you go haha.

    • The editor component (RAEdit) wasn’t written by me, and it’s a major task to update it to support Unicode, considering that it’s written in assembly. But if your system locale is Korean, I believe that changing the editor font can help.
      See also:
      http://rammichael.com/multimate-assembler/comment-page-1#comment-4579

      • Yeah I suppose that would be quite a task and it’s certainly not necessary since it is still possible to make use of Unicode should you need to do so.

        Thank you for the advice though, I appreciate it.

        Would I be correct to assume that RAEdit is open source? If that’s the case I might have to try my hand at implementing support for Unicode. I’m a little rusty when it comes to actually writing software in assembly, but it should be fun anyway.

        Should that not work out, I suppose I could try asking the developer about it. I’d be willing to pay for it haha.

  32. yeryry says:

    This is really nice. Makes patching much easier, but…
    It seems that the modifications created by assembling using this aren’t added to OllyDbg’s patch list, which makes managing them more difficult. I don’t know whether Olly gives any access to this list, but if it does, this would be a nice addition to this plugin 🙂

  33. REAP says:

    Hi,

    I’m using your plug-in with x64-dbg with a 64 bit application

    It seems that the DB and DD commands are not recognised.

    So far I have not been able to locate an equivalent command, do you happen to know the equivalent commands or do you know a command listing where I can find the answer.

    BTW a very useful plugin.

    Cheers

    • Hi,

      Every line which is not a label, a comment, a string, or a “special command”, is treated as an assembler command, and is forwarded to the debugger’s assembler.
      If you’ll try to assemble the “dd 00000000” command in the regular Ollydbg assembler, you’ll find out that it works. But it’s not supported by x64dbg.
      For consistency, I believe that it’s something that is better to be implemented in x64dbg.

      As an alternative, you can use the data string syntax for the plugin:
      db 12 -> “\x12”
      dd 12345678 -> “\x78\x56\x34\x12”

  34. tonyweb says:

    Hi RaMMicHaeL,
    thank you sooooooooo much for this AWESOME tool … it really helps me a lot!

    Recently I’m trying some assembling on x64dbg and, unfortunately, I discovered that – as far as I experimented – I can’t do math on labels.

    I mean, on x86 I’ll usually write something like that

    <$.00001000>
    @textSection:
    
    <$.XXXXXXXX>
    PUSHAD
    CALL @delta
    @delta:
    POP EBP
    ;
    lea eax,dword[ebp+@textSection-@delta]
    
    ; and then I can work on eax
    
    ;
    POPAD
    

    but if I try to assemble something like that with the x64dbg-plugin:

    <$.00001000>
    @textSection:
    
    <$.00002000>
    PUSH RAX
    PUSH RBP
    
    CALL @delta
    @delta:
    POP RBP
    ;
    
    ; MOV
    mov rax,@textSection
    add rax,@textSection        ; Error!
    
    ; LEA
    lea rax,qword[rbp]
    lea rax,qword[@textSection]
    lea rax,qword[@textSection+10]  ; gives 'lea rax, [0x10]' ?!?
    
    lea rax,qword[rbp+@textSection] ; Error!
    lea rax,qword[rbp+@textSection-@delta] ; Error!
    
    ;
    POP RBP
    POP RAX
    

    I got an error (or wrong result) on every instructions that does math on labels (failed to encode instruction) …
    Is it the intended behavior and/or am I missing something?

    In the meantime I’m doing something like that:

        CALL @delta
        @delta:
        POP RBP
    
    ; Calculate "displacement"
    mov rax,@delta
    sub rbp,rax
    
    mov rax,@textSection
    add rax,rbp
    

    .. but I’d like to know if I could do labels’ math in some way or another 😉

    Thank you for any help and/or hints … and please keep doing the GREAT work you’re already doing !

    Best Regards,
    Tony

    • Hi Tony,

      Thanks for the feedback.
      The plugin doesn’t do any math by itself. It just replaces the labels with the corresponding addresses, and passes the commands to the debugger engine.

      If you’ll try to assemble the following commands in x64dbg, you’ll see that you’re getting the same errors:

      • add rax, 1234567812345678 – an error.
      • lea rax, qword [1234567812345678+10] – assembles to lea rax, [0x10], seems like a bug.
      • lea rax, qword [rbp+1234567812345678] – an error.

      I’m not sure whether 1 and 3 are bugs, or whether the x64 architecture doesn’t provide these commands, but 2 surely is a bug of x64dbg.

  35. tonyweb says:

    Thanks again RaMMicHaeL for your quick and kind answer!

    I’m afraid I was too rash and didn’t try to manual assembly-ing those commands … I’m really sorry for that.

    It seems I’ve asked the questions to the “wrong” person … ehehhe. I’ll have to talk with Mr.eXoDia and here from him 😉

    Best Regards,
    Tony

  36. Savanna Gasca says:

    Practical post . Incidentally , you want a template form , my husband filled out and esigned a sample version here http://pdf.ac/9YSbzd.

  37. mudlord says:

    Any chance of warnings if calls/jumps are outside the region of code to be copied in the “Dissassemble selection” function?

    Or is it intended not to be used as a plugin to copy assembly code?

  38. mudlord says:

    Ah okay, makes sense why not. I guess code/data copying would be best left to another plugin for that purpose.

    Thanks for the regex hint though, I’ll try that 🙂

  39. Andrew says:

    Hi Rammichael,

    really love your plugin, I was wondering if you plan to fix some unrecognized assy op codes.

    currently multi inline assembler does not recognize near calls to registers

    eg)

    FFD0 Call near eax
    FFD1 Call near ecx
    FFD2 Call near edx
    FFD3 Call near ebx
    FFD4 Call near esp
    FFD5 Call near ebp
    FFD6 Call near esi
    FFD7 Call near edi

    cheers

  40. Dibya says:

    Dear RaMMicHaeL, Please can you add following features to your tool . I am trying to get some function code from a dll (export) I select from beginning to end of ret where function ends but for unknown reason some jumps arenot dissambled , left original like jnz.RVA i think they are sub routines . Please can you make your tool disassemble those . please its a request .
    Yours Lovingly ,
    DibyaMSFN.

    • Hi Dibya,

      Please provide a way for me to reproduce the issue. Upload the DLL, and provide a video, or at least a screenshot.

      • Dibya says:

        Shell32/ntdll of 8.1 . i need it to move some function to XP to run some apps .
        like this one . My router broken i am browsing via my phone . I will upload those dlls if you want as soon as possible .
        Code are coming like this you can find many calls , jumps,subroutines not got disassembled

            MOV EDI,EDI
            PUSH EBP
            MOV EBP,ESP
            PUSH EDI
            MOV EDI,DWORD PTR SS:[EBP+14]
            TEST EDI,EDI
            JNZ SHORT @L00000001
            XOR EAX,EAX
            JMP SHORT @L00000009
        
        @L00000001:
            MOV EAX,DWORD PTR SS:[EBP+8]
            PUSH ESI
            TEST EAX,EAX
            JNZ SHORT @L00000002
            XOR ESI,ESI
            PUSH ESI
            PUSH ESI
            PUSH ESI
            PUSH ESI
            PUSH ESI
            CALL $$6C61B
            ADD ESP,14
            PUSH 16
            POP EAX
            JMP SHORT @L00000008
        
        @L00000002:
            PUSH EBX
            MOV EBX,DWORD PTR SS:[EBP+10]
            TEST EBX,EBX
            JE SHORT @L00000003
            CMP DWORD PTR SS:[EBP+C],EDI
            JB SHORT @L00000003
            PUSH EDI
            PUSH EBX
            PUSH EAX
            CALL $$703A0 (Not got disassembled)
            ADD ESP,0C
            XOR EAX,EAX
            JMP SHORT @L00000007
        
        @L00000003:
            PUSH DWORD PTR SS:[EBP+C]
            XOR ESI,ESI
            PUSH ESI
            PUSH EAX
            CALL $$70A40
            ADD ESP,0C
            TEST EBX,EBX
            JNZ SHORT @L00000004
            PUSH 16
            JMP SHORT @L00000005
        
        @L00000004:
            CMP DWORD PTR SS:[EBP+C],EDI
            JNB SHORT @L00000006
            PUSH 22
        
        @L00000005:
            POP EDI
            PUSH ESI
            PUSH ESI
            PUSH ESI
            PUSH ESI
            PUSH ESI
            CALL $$6C61B
            ADD ESP,14
            MOV EAX,EDI
            JMP SHORT @L00000007
        
        @L00000006:
            PUSH 16
            POP EAX
        
        @L00000007:
            POP EBX
        
        @L00000008:
            POP ESI
        
        @L00000009:
            POP EDI
            POP EBP
            RETN
        

        Another

            MOV EDI,EDI
            PUSH EBP
            MOV EBP,ESP
            PUSH ESI
            MOV ESI,DWORD PTR SS:[EBP+8]
            XOR EDX,EDX
            PUSH 1
            MOV ECX,ESI
            CALL $$63544
            TEST EAX,EAX
            JE SHORT $$5E7AD
            TEST BYTE PTR DS:[ESI+9C],1
            JE SHORT $$5E7AD
        
        @L00000001:
            AND DWORD PTR DS:[ESI+9C],FFFFFFFD
            POP ESI
            POP EBP
            RETN 4
        

        one more

        @TpAllocTimer:
            MOV EDI,EDI
            PUSH EBP
            MOV EBP,ESP
            AND ESP,FFFFFFF8
            PUSH ECX
            PUSH EBX
            MOV EBX,DWORD PTR SS:[EBP+8]
            PUSH ESI
            PUSH EDI
            TEST EBX,EBX
            JE $$9465B
            CMP DWORD PTR SS:[EBP+C],0
            JE $$9465B
            MOV EDI,DWORD PTR SS:[EBP+14]
            TEST EDI,EDI
            JE SHORT @L00000001
            TEST DWORD PTR DS:[EDI+1C],FFFFFFFC
            JNZ $$9465B
        
        @L00000001:
            MOV EAX,DWORD PTR FS:[30]
            MOV EAX,DWORD PTR DS:[EAX+C]
            CMP BYTE PTR DS:[EAX+28],0
            JNZ $$9465B
            MOV EAX,DWORD PTR DS:[$$0FBFEC]
            ADD EAX,100000
            PUSH 0C0
            OR EAX,8
            PUSH EAX
            MOV EAX,DWORD PTR FS:[30]
            PUSH DWORD PTR DS:[EAX+18]
            CALL $$2ABF0
            MOV ESI,EAX
            TEST ESI,ESI
            JE SHORT $$364B1
            MOV EAX,DWORD PTR SS:[EBP+4]
            XOR DL,DL
            PUSH $$3AC8
            PUSH $$3AB8
            PUSH EDI
            PUSH DWORD PTR SS:[EBP+10]
            MOV ECX,ESI
            MOV DWORD PTR DS:[ESI+54],EAX
            CALL $$358D1
            TEST EAX,EAX
            JS SHORT @L00000002
            MOV ECX,DWORD PTR SS:[EBP+C]
            MOV DWORD PTR DS:[ESI+30],ECX
            MOV DWORD PTR DS:[EBX],ESI
        
        @L00000002:
            POP EDI
            POP ESI
            POP EBX
            MOV ESP,EBP
            POP EBP
            RETN 10
        

        Best of luCk .
        Thanks a lot for your great tool

  41. Bronco says:

    Прикольно тема живёт.
    К автору. Последнее время плагин чаще используется под отладчиком Диа. Там вроде поправили [rip+/-distance] на нормальное отображение указателей, у Вас осталось. Ну и второе, у Диа есть вызов плагинов, но как автоматом тыкнуть код в Ваш плагин пока не вкурю.

    • Что такое отладчик Диа?

      поправили [rip+/-distance] на нормальное отображение указателей

      как автоматом тыкнуть код в Ваш плагин пока не вкурю

      Я не понял о чем речь.

  42. Bronco says:

    Ок…не думал что так сложно.
    Тогда на примере.
    Просто копирую инструкцию в отладчике Mr.eXoDia x64 dbg как дизасм , вот результ:
    LEA RCX, QWORD PTR DS:[141C914F0]
    Делаю то же самое Вашим плагином.
    lea rcx, [rip + 0x1c43239].
    при переносе на другое место, в итоге указатель потерян.
    По автоматике по электронке ответил.

  43. Bronco says:

    На эту тему есть

    это на днях пофиксили, так что это вопрос снят.
    по автоматизации можно что либо решить ?
    вызов плагина в скриптовом движке есть, и на мой взгляд ему достаточно передать три аргумента “откуда, куда, размер”, и можно ограничиться одним табом.

  44. Morten says:

    Hey again.

    Still an invaluable tool. However, there’s a really annoying bug in the 64-bit version for x64dbg. The text editor scrolls up when scrolling the mouse wheel down, so you have to use the mouse to drag the scrollbar, which is rather annoying (works fine in x32dbg).

  45. Morten says:

    Is there any way to get it to no put a lot of NOPs between instructions? I assume it’s some kind of alignment optimization, but in a lot of cases, I’d prefer compact code over fast code.

    • Are you using x64dbg? Are you referring to the NOPs after jumps?

      • Morten says:

        x64dbg

        0000000014001000 | 55 | PUSH RBP
        0000000014001001 | 48 89 E5 | MOV RBP,RSP
        0000000014001004 | 48 83 EC 30 | SUB RSP,30
        0000000014001008 | E8 90 00 00 00 | CALL 1400109D
        000000001400100D | 48 C7 C1 00 20 00 14 | MOV RCX,14002000
        0000000014001014 | 90 | NOP
        0000000014001015 | 90 | NOP
        0000000014001016 | 90 | NOP
        0000000014001017 | 48 C7 C2 00 30 00 14 | MOV RDX,14003000
        000000001400101E | 90 | NOP
        000000001400101F | 90 | NOP
        0000000014001020 | 90 | NOP
        0000000014001021 | 49 C7 C0 CF 00 00 00 | MOV R8,CF
        0000000014001028 | E8 55 00 00 00 | CALL 14001082
        000000001400102D | 48 C7 C1 00 20 00 14 | MOV RCX,14002000
        0000000014001034 | 90 | NOP
        0000000014001035 | 90 | NOP
        0000000014001036 | 90 | NOP
        0000000014001037 | 48 C7 C2 CF 00 00 00 | MOV RDX,CF
        000000001400103E | 49 C7 C0 C0 31 00 14 | MOV R8,140031C0
        0000000014001045 | 90 | NOP
        0000000014001046 | 90 | NOP
        0000000014001047 | 90 | NOP
        0000000014001048 | 49 C7 C1 80 31 00 14 | MOV R9,14003180
        000000001400104F | 90 | NOP
        0000000014001050 | 90 | NOP
        0000000014001051 | 90 | NOP
        0000000014001052 | E8 02 01 00 00 | CALL 14001159
        0000000014001057 | 48 31 C9 | XOR RCX,RCX

        • OK, I’m familiar with the issue. The reason for the behavior is that your constants are @labels, and the assembler cannot know their size beforehand, so it takes the worst case assumption.
          For example, the command MOV RCX,1234567812345678 would take 10 bytes, not 7.
          See this comment for more details:
          http://rammichael.com/multimate-assembler/comment-page-1#comment-3925

          One solution for this is having a different syntax for shorter commands, something like MOV RCX,DWORD @address. That’s being done for jumps actually, having JXX @address and JXX SHORT @address.

          If you have a better idea, let me know. Otherwise, this has to be changed in the assembler/disassembler engines of x64dbg (unless I add a special case in the plugin, which I’m reluctant to do).

          • Morten says:

            Hmm. I see the problem.

            jmp @Label

            @Label:

            You’re assuming the JMP is 5 bytes, since you don’t know where @Label is before you encounter it.
            Which results in:
            14001000 | EB 03 | JMP
            14001002 | 90 | NOP
            14001003 | 90 | NOP
            14001004 | 90 | NOP
            14001005 Label: | 90 | NOP

            Couldn’t you do many passes to correct a bad assumption?

            For example, imagine 2 scenarios.

            Scenario 1 (Short jmp):

            <14001000>
            jmp @Label

            @Label:

            On the first pass, when you encounter ‘jmp @Label’, you’ll start by assuming a short JMP is enough.
            So you allocate 2 bytes for that.
            Now you encounter @Label, and you realize 2 bytes were indeed enough. Then you assemble, and it’s perfect.

            Scenario 2 (Far jmp):

            <14001000>
            jmp @Label
            <14004000>

            @Label:

            On the first pass, when you encounter ‘jmp @Label’, you’ll start by assuming a short JMP is enough.
            So you allocate 2 bytes for that.
            Now you encounter @Label, and you realize 2 bytes is not enough (requires 5),
            so you restart the whole thing from the jmp instruction and change it to 5 bytes.
            Now you encounter @Label, and now 5 is enough. Then you assemble, and it’s perfect.

            Something like that.

            • It’s possible theoretically, that’s what FASM does. Read about “multiple passes” here. That doesn’t look trivial to implement, and I don’t plan to work on it in the foreseeable future, sorry.

              If you would like to try implementing it yourself, I may consider releasing the source code.

  46. ret0x0 says:

    Привет!

    При реверсе в x64dbg наткнулся на инструкцию ‘push rbp’, состоящую из двух байт:
    40 55 | push rbp

    при дизассемблировании в multiasm, да и отладчик точно так же понимает, инструкция ‘push rbp’ при выносе ее в другое место состоит из одного байта 55.

    По факту теряется байт 40. Не знаю, в чем отличие одно и двухбайтовой инструкции push rbp, но заметил недавно такой ньюанс. Как код в виде байтов передать знаю, но хотелось бы знать, есть ли в этом реальное применение.

  47. ret0x0 says:

    спасибо!

  48. VeeDub says:

    Hello,

    I’m trying to write a patch using RVA

    Version of Multimate is v2.3.6
    x64dbg – x32 – Jul 1, 2021

    Base : 0x21000
    Patch : 0x338B56

    So I use
    $.317B56

    I get error: Address expected

    Am I doing something wrong?

    PS: Using absolute addresses works.

    • Hi,
      In which command/context is $.317B56 used? Please post your whole code snippet so that I’ll be able to reproduce the error. Note that the $.<address> form uses the base address based on the module that is currently viewed in the debugger’s CPU view.

      • VeeDub says:

        Hello,

        $.317B56 is within the .text section of the exe that I’m attempting to patch.

        If I specify the absolute value instead, as a test, then it works and inserts the code

        I’ve also tried $.1000, and get same error.

        You should be able to reproduce the error using

        $.1000

        NOP

        • $.1000

          NOP

          Did you leave out the <, > characters by mistake? Perhaps they were stripped by the blog.

          In any case, it works for me: https://i.imgur.com/WRnbpNW.png

          The “Address expected” error message is shown if the first character is not <.

          • VeeDub says:

            Hello,

            Yes I did leave out the <> characters by mistake

            I was following the example in the Help file literally

            Perhaps you could consider updating the example in the help file to show as
            <$.1000>

            Thanks for your prompt reply

            Multimate is a really useful plug-in.

            Cheers
            VW

  49. Ewan Green says:

    Hello! My friends and I really like your plugin. It has allowed for much faster modification of an existing executable, compared to assembling instruction-by-instruction. The biggest (if not only) thing that we think it’s missing are macros of some sort — %defines or the like that can be used for simple inlined text replacement before it gets assembled, like the preprocessor in nasm. Would you pass us the source to this plugin so we can potentially add this feature? Feel free to follow up via. email instead of on here, if that’s what you’d like.

Leave a Reply