Fix potential division error in bdshemu, when the destination operand is not large enough to hold the result.

pull/21/head
Andrei Vlad LUTAS 4 years ago
parent d61a6fa5dd
commit ea28907359

@ -663,7 +663,7 @@ ShemuSetGprValue(
if (High8)
{
// AH, CH, DH or BH accessed.
*((uint8_t *)(&Context->Registers.RegRax + Reg - 4) + 1) = Value & 0xff;
*((uint8_t *)(&Context->Registers.RegRax + Reg - 4) + 1) = Value & 0xFF;
}
else
{
@ -1509,6 +1509,116 @@ ShemuMultiply64Signed(
}
//
// ShemuCheckDiv
//
static bool
ShemuCheckDiv(
uint64_t Divident,
uint64_t Divider,
uint8_t Size // The size of the Source (Divider). The Divident is twice as large.
)
{
// Returns true if all checks are OK, and Divident / Divider will not cause #DE.
if (Divider == 0)
{
// Division by zero.
return false;
}
// If the result won't fit in the destination, a #DE would be generated.
switch (Size)
{
case 1:
if (((Divident >> 8) & 0xFF) >= Divider)
{
return false;
}
break;
case 2:
if (((Divident >> 16) & 0xFFFF) >= Divider)
{
return false;
}
break;
case 4:
if (((Divident >> 32) & 0xFFFFFFFF) >= Divider)
{
return false;
}
break;
default:
// 64 bit source division is not supported.
return false;
}
return true;
}
//
// ShemuCheckIdiv
//
static bool
ShemuCheckIdiv(
int64_t Divident,
int64_t Divider,
uint8_t Size // The size of the Source (Divider).
)
{
bool neg1, neg2;
uint64_t quotient, max;
neg1 = Divident < 0;
neg2 = Divider < 0;
if (neg1)
{
Divident = -Divident;
}
if (neg2)
{
Divider = -Divider;
}
// Do checks when dividing positive values.
if (!ShemuCheckDiv(Divident, Divider, Size))
{
return false;
}
// Get the positive quotient.
quotient = (uint64_t)Divident / (uint64_t)Divider;
max = (Size == 1) ? 0x80 : (Size == 2) ? 0x8000 : (Size == 4) ? 0x80000000 : 0x8000000000000000;
if (neg1 ^ neg2)
{
// The Divident and the Divider have different signs, the quotient must be negative. If it's positive => #DE.
if (ND_GET_SIGN(Size, quotient) && quotient != max)
{
return false;
}
}
else
{
// Both the Divident and the Divider are positive/negative, so a positive result must be produced. If it's
// negative => #DE.
if (ND_GET_SIGN(Size, quotient))
{
return false;
}
}
return true;
}
//
// ShemuPrintContext
//
@ -2417,22 +2527,31 @@ ShemuEmulate(
if (src.Size == 1)
{
if (src.Value.Bytes[0] == 0)
{
// Division by zero, force emulation stop.
stop = true;
break;
}
uint16_t divident;
divident = (uint16_t)Context->Registers.RegRax;
if (ND_INS_DIV == Context->Instruction.Instruction)
{
res.Value.Bytes[0] = (uint8_t)((uint16_t)Context->Registers.RegRax / (uint8_t)src.Value.Bytes[0]);
res.Value.Bytes[1] = (uint8_t)((uint16_t)Context->Registers.RegRax % (uint8_t)src.Value.Bytes[0]);
if (!ShemuCheckDiv(divident, src.Value.Bytes[0], 1))
{
stop = true;
break;
}
res.Value.Bytes[0] = (uint8_t)(divident / src.Value.Bytes[0]);
res.Value.Bytes[1] = (uint8_t)(divident % src.Value.Bytes[0]);
}
else
{
res.Value.Bytes[0] = (int8_t)((int16_t)Context->Registers.RegRax / (int8_t)src.Value.Bytes[0]);
res.Value.Bytes[1] = (int8_t)((int16_t)Context->Registers.RegRax % (int8_t)src.Value.Bytes[0]);
if (!ShemuCheckIdiv((int64_t)(int16_t)divident, (int64_t)(int8_t)src.Value.Bytes[0], 1))
{
stop = true;
break;
}
res.Value.Bytes[0] = (int8_t)((int16_t)divident / (int8_t)src.Value.Bytes[0]);
res.Value.Bytes[1] = (int8_t)((int16_t)divident % (int8_t)src.Value.Bytes[0]);
}
// Result in AX (AL - quotient, AH - reminder).
@ -2442,23 +2561,28 @@ ShemuEmulate(
{
uint32_t divident;
if (src.Value.Words[0] == 0)
{
// Division by zero, force emulation stop.
stop = true;
break;
}
divident = ((uint32_t)(uint16_t)Context->Registers.RegRdx << 16) |
(uint32_t)(uint16_t)Context->Registers.RegRax;
if (ND_INS_DIV == Context->Instruction.Instruction)
{
res.Value.Words[0] = (uint16_t)((uint32_t)divident / (uint16_t)src.Value.Words[0]);
res.Value.Words[1] = (uint16_t)((uint32_t)divident % (uint16_t)src.Value.Words[0]);
if (!ShemuCheckDiv(divident, src.Value.Words[0], 2))
{
stop = true;
break;
}
res.Value.Words[0] = (uint16_t)(divident / src.Value.Words[0]);
res.Value.Words[1] = (uint16_t)(divident % src.Value.Words[0]);
}
else
{
if (!ShemuCheckIdiv((int64_t)(int32_t)divident, (int64_t)(int16_t)src.Value.Words[0], 2))
{
stop = true;
break;
}
res.Value.Words[0] = (int16_t)((int32_t)divident / (int16_t)src.Value.Words[0]);
res.Value.Words[1] = (int16_t)((int32_t)divident % (int16_t)src.Value.Words[0]);
}
@ -2470,23 +2594,28 @@ ShemuEmulate(
{
uint64_t divident;
if (src.Value.Dwords[0] == 0)
{
// Division by zero, force emulation stop.
stop = true;
break;
}
divident = ((uint64_t)(uint32_t)Context->Registers.RegRdx << 32) |
(uint64_t)(uint32_t)Context->Registers.RegRax;
if (ND_INS_DIV == Context->Instruction.Instruction)
{
res.Value.Dwords[0] = (uint32_t)((uint64_t)divident / (uint32_t)src.Value.Dwords[0]);
res.Value.Dwords[1] = (uint32_t)((uint64_t)divident % (uint32_t)src.Value.Dwords[0]);
if (!ShemuCheckDiv(divident, src.Value.Dwords[0], 4))
{
stop = true;
break;
}
res.Value.Dwords[0] = (uint32_t)(divident / src.Value.Dwords[0]);
res.Value.Dwords[1] = (uint32_t)(divident % src.Value.Dwords[0]);
}
else
{
if (!ShemuCheckIdiv((int64_t)divident, (int64_t)(int32_t)src.Value.Dwords[0], 4))
{
stop = true;
break;
}
res.Value.Dwords[0] = (int32_t)((int64_t)divident / (int32_t)src.Value.Dwords[0]);
res.Value.Dwords[1] = (int32_t)((int64_t)divident % (int32_t)src.Value.Dwords[0]);
}

Binary file not shown.

@ -0,0 +1,6 @@
bits 64
MOV edx, 0x80000000
NOT edi
IDIV edi
RETN

@ -0,0 +1,19 @@
RAX = 0x0000000000000000 RCX = 0x0000000000000000 RDX = 0x0000000000000000 RBX = 0x0000000000000000
RSP = 0x0000000000101000 RBP = 0x0000000000000000 RSI = 0x0000000000000000 RDI = 0x0000000000000000
R8 = 0x0000000000000000 R9 = 0x0000000000000000 R10 = 0x0000000000000000 R11 = 0x0000000000000000
R12 = 0x0000000000000000 R13 = 0x0000000000000000 R14 = 0x0000000000000000 R15 = 0x0000000000000000
RIP = 0x0000000000200000 RFLAGS = 0x0000000000000202
Emulating: 0x0000000000200000 MOV edx, 0x80000000
RAX = 0x0000000000000000 RCX = 0x0000000000000000 RDX = 0x0000000080000000 RBX = 0x0000000000000000
RSP = 0x0000000000101000 RBP = 0x0000000000000000 RSI = 0x0000000000000000 RDI = 0x0000000000000000
R8 = 0x0000000000000000 R9 = 0x0000000000000000 R10 = 0x0000000000000000 R11 = 0x0000000000000000
R12 = 0x0000000000000000 R13 = 0x0000000000000000 R14 = 0x0000000000000000 R15 = 0x0000000000000000
RIP = 0x0000000000200005 RFLAGS = 0x0000000000000202
Emulating: 0x0000000000200005 NOT edi
RAX = 0x0000000000000000 RCX = 0x0000000000000000 RDX = 0x0000000080000000 RBX = 0x0000000000000000
RSP = 0x0000000000101000 RBP = 0x0000000000000000 RSI = 0x0000000000000000 RDI = 0x00000000ffffffff
R8 = 0x0000000000000000 R9 = 0x0000000000000000 R10 = 0x0000000000000000 R11 = 0x0000000000000000
R12 = 0x0000000000000000 R13 = 0x0000000000000000 R14 = 0x0000000000000000 R15 = 0x0000000000000000
RIP = 0x0000000000200007 RFLAGS = 0x0000000000000202
Emulating: 0x0000000000200007 IDIV edi
Emulation terminated with status 0x0000000a, flags: 0x0, 0 NOPs

@ -7,6 +7,6 @@
#define DISASM_VERSION_MAJOR 1
#define DISASM_VERSION_MINOR 28
#define DISASM_VERSION_REVISION 1
#define DISASM_VERSION_REVISION 2
#endif // DISASM_VER_H

@ -12,7 +12,7 @@ from setuptools import find_packages, setup, Command, Extension, Distribution
from codecs import open
VERSION = (0, 1, 3)
LIBRARY_VERSION = (1, 28, 1)
LIBRARY_VERSION = (1, 28, 2)
LIBRARY_INSTRUX_SIZE = 856
packages = ['pybddisasm']

Loading…
Cancel
Save