the last byte of API/library call instructions is always 0x0A
It's because calls needs to have method (ref) as a parameter and methods are defined in the table that has an id of 0x0A
.
Having bytes of the call like this 280600000A
let's go one by one.
0x28
- is the value for opcode 'call' and it takes one operand.
- the rest of the opcode is the metadata token so basically the information which method should be called
But why 0x0A
is at the end? It should be read as a little-endian so the value should be 0x0A000006
. But what are the bytes?
From Wikipedia:
When CIL code uses metadata it does so through a metadata token. This is a 32-bit value where the top 8 bits identify the appropriate metadata table, and the remaining 24 bits give the index of the metadata in the table.
So the first value is the table id - and as I've mentioned the id of member's ref table is value 0x0A
. And the rest is an index in the table (in our case 0x6
).
More about the tables? Those are basically part of .NET metadata information, that can be seen when you open one in i.e. dnSpy

As one can see 0x0A
is assigned to the MemberRef
(containing both methods and fields references)
what about operands of ldstr instructions?
In this instance, the instruction has the following structure 72XXXX0070
and 0x70
indicates different stream - namely User defined strings or #US
. The rest (again interpreted as a little-ending 32-bit val) is the offset (in bytes) in #US
table.
Generally dnSpy is a great tool to verifying those values as one can metadata tables.
The linked article (and the whole series is a great resource) it does explain (I think) the structure but maybe indirectly - just find the information about metadata token.
We can induce from it the whole structure of a metadata token.