Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- 64bit CE only,
- -- the value-to-bytes in the custom type asm script is not implement,
- -- instead the value change function is implemented by AddressList.OnValueChange, it allow more precision input of the decimal value.
- local cs_decimal_typeName = 'CSharp_Decimal_ASM'
- cs_decimal_typeName = cs_decimal_typeName:gsub('%W','_')
- local carry = 0x100000000
- local function QNAdd(me, rhs)
- local ret = {}
- for i=1,4 do ret[i]=me[i]end
- for i=1,4 do
- ret[i] = ret[i]+rhs[i]
- if ret[i] >= carry then
- ret[i], ret[i+1] = ret[i] - carry, i==4 and ret[i+1] or 1+ret[i+1]
- end
- end
- return ret
- end
- local function QNDump(me)
- local r = {}
- for i=1,#me do r[i]=string.format('%X',me[i]) end
- return 'QN:hex<'..table.concat(me,', ')..'>'
- end
- local QN
- QN = setmetatable({[0]={0,0,0,0},[1]={1,0,0,0}},{
- __call = function(me,digit,power)local key = digit + (power<<8) return me[key]end,
- __index = function(me,key)
- local digit, power, ret = key & 0xf, key >> 8, {0,0,0,0}
- if digit == 0 then
- return ret
- elseif digit==1 then
- local lower = QN(1,power-1)
- for i=1,10 do ret = QNAdd(ret,lower) end
- else
- local lower = QN(1,power)
- for i=1,digit do ret = QNAdd(ret,lower) end
- end
- rawset(me, key, ret)
- return ret
- end
- })
- local al = getAddressList()
- al.OnValueChange = function(me, mr)
- if mr.Type ~= vtCustom or mr.CustomTypeName ~= cs_decimal_typeName then
- return false
- else
- local addr = mr.currentAddress
- local val = mr.Value
- local ins,inp, sign, lhs, decPos, decimal, rhs, lastMant,hasExp, expSign, exp, mantissa, power
- repeat
- ins = inputQuery(cs_decimal_typeName, 'Enter decimal value to change:', val)
- if not ins then print(cs_decimal_typeName..' abort input for change.')return true end
- inp = ins:gsub('[ _,]','')
- sign, lhs, decimal,decPos, rhs, lastMant, hasExp,expSign, exp = inp:match'^([%+%-]?)(%d+)(%.?)()(%d*)()([eE]?)([%+%-]?)(%d-)$'
- if not sign then print(cs_decimal_typeName..' invalid format : '..ins)end
- until sign
- sign, expSign, power = sign=='-'and -1 or 1, expSign=='-'and -1 or 1,#exp>0 and #hasExp>0 and tonumber(exp)or 0
- power = lastMant - decPos - power * expSign
- mantissa = #hasExp>0 and lhs..rhs or lhs..rhs..exp
- local expected = sign*tonumber(mantissa)*math.pow(10,power)
- -- print(sign, power, decPos, mantissa, expected)
- while mantissa:sub(1,1)=='0' do mantissa=mantissa:sub(2) end
- expected = sign*tonumber(mantissa)*math.pow(10,power)
- -- print(sign, power, decPos, mantissa, expected)
- while mantissa:sub(-1)=='0' and power<0 do power, mantissa=power+1, mantissa:sub(1,-2) end
- expected = sign*tonumber(mantissa)*math.pow(10,power)
- -- print(sign, power, decPos, mantissa, expected)
- while power>28 and #mantissa<28 do power, mantissa=power-1, mantissa..'0' end
- expected = sign*tonumber(mantissa)*math.pow(10,power)
- -- print(sign, power, decPos, mantissa, expected)
- local ret = QN[0]
- for i=1,math.min(28,#mantissa) do
- local e = tonumber(mantissa:sub(-i,-i))
- ret = QNAdd(ret ,QN(e,i-1))
- end
- -- print(QNDump(ret))
- if ret[4]~=0 or #mantissa>28 or power>28 then print(cs_decimal_typeName..' digits overflow :'..ins)return true end
- local flags = ( (sign <0 and (1 << 15) or 0 )+ power)<<16
- if not mantissa:find'[1-9]'then writeQword(addr,0);writeQword(addr+8,0);return true end -- zero case
- local bt = stringToByteTable(string.pack('I4I4I4',table.unpack(ret,1,3)))
- writeBytes(addr,bt)
- -- writeQword(addr, tonumber(mantissa))
- writeInteger(addr+0xc,flags)
- return true
- end
- end
- local script = string.format([[
- alloc(ConvertRoutine,$4000)
- alloc(ConvertBackRoutine,1024)
- alloc(TypeName,256)
- alloc(ByteSize,4)
- alloc(UsesFloat,1)
- alloc(CallMethod,1)
- TypeName:
- db '%s',0
- ByteSize:
- dd 10
- UsesFloat:
- db 1 //Change to 1 if this custom type should be treated as a float
- CallMethod:
- db 1 //Remove or change to 0 for legacy call mechanism
- label(ds2to64)
- label(s_doublePowers10)
- label(NaN)
- ConvertRoutine+3000:
- NaN:
- dd 0ffc00000,(float)0.5
- ds2to64:
- dq (double)1.8446744073709552e+019
- s_doublePowers10:
- dq (double)1e+00, (double)1e+01, (double)1e+02, (double)1e+03,
- dq (double)1e+04, (double)1e+05, (double)1e+06, (double)1e+07,
- dq (double)1e+08, (double)1e+09, (double)1e+10, (double)1e+11,
- dq (double)1e+12, (double)1e+13, (double)1e+14, (double)1e+15,
- dq (double)1e+16, (double)1e+17, (double)1e+18, (double)1e+19,
- dq (double)1e+20, (double)1e+21, (double)1e+22, (double)1e+23,
- dq (double)1e+24, (double)1e+25, (double)1e+26, (double)1e+27,
- dq (double)1e+28, (double)1e+29, (double)1e+30, (double)1e+31,
- dq (double)1e+32, (double)1e+33, (double)1e+34, (double)1e+35,
- dq (double)1e+36, (double)1e+37, (double)1e+38, (double)1e+39,
- dq (double)1e+40, (double)1e+41, (double)1e+42, (double)1e+43,
- dq (double)1e+44, (double)1e+45, (double)1e+46, (double)1e+47,
- dq (double)1e+48, (double)1e+49, (double)1e+50, (double)1e+51,
- dq (double)1e+52, (double)1e+53, (double)1e+54, (double)1e+55,
- dq (double)1e+56, (double)1e+57, (double)1e+58, (double)1e+59,
- dq (double)1e+60, (double)1e+61, (double)1e+62, (double)1e+63,
- dq (double)1e+64, (double)1e+65, (double)1e+66, (double)1e+67,
- dq (double)1e+68, (double)1e+69, (double)1e+70, (double)1e+71,
- dq (double)1e+72, (double)1e+73, (double)1e+74, (double)1e+75,
- dq (double)1e+76, (double)1e+77, (double)1e+78, (double)1e+79,
- dq (double)1e+80
- label(skipDone)
- //The convert routine should hold a routine that converts the data to an integer (in eax)
- //function declared as: cdecl int ConvertRoutine(unsigned char *input, PTR_UINT address);
- //Note: Keep in mind that this routine can be called by multiple threads at the same time.
- ConvertRoutine:
- //jmp dllname.functionname
- [64-bit]
- //or manual:
- //parameters: (64-bit)
- //rcx=address of input
- //rdx=address
- //mov eax,[rcx] //eax now contains the bytes 'input' pointed to
- ////////////////////////////
- push rsi
- push rdi
- push rdx
- push rcx
- // mov edi,[rcx+04]
- // jmp skipDone
- mov rsi,rcx
- mov edi,[NaN]
- mov edx,[rsi+0c]
- test edx,7fe0ffff
- jne skipDone
- shr edx,10
- and edx,ff
- cmp edx,1c
- ja skipDone
- mov ecx,edx
- movsd xmm0,[ds2to64]
- cvtsi2sd xmm1,dword ptr[rsi+08]
- mulsd xmm0,xmm1
- cvtsi2sd xmm1,qword ptr[rsi]
- addsd xmm0,xmm1
- movsd xmm1,[rcx*8+s_doublePowers10]
- divsd xmm0,xmm1
- test byte ptr[rsi+0f],80
- je short @f
- xorpd xmm1,xmm1
- subsd xmm1,xmm0
- movsd xmm0,xmm1
- @@:
- cvtsd2ss xmm0,xmm0
- movd edi,xmm0
- skipDone:
- mov eax,edi
- pop rcx
- pop rdx
- pop rdi
- pop rsi
- ////////////////////////////
- ret
- [/64-bit]
- [32-bit]
- //jmp dllname.functionname
- //or manual:
- //parameters: (32-bit)
- push ebp
- mov ebp,esp
- //[ebp+8]=address of input
- //[ebp+c]=address
- //example:
- mov eax,[ebp+8] //place the address that contains the bytes into eax
- mov eax,[eax] //place the bytes into eax so it's handled as a normal 4 byte value
- pop ebp
- ret
- [/32-bit]
- //The convert back routine should hold a routine that converts the given integer back to a row of bytes (e.g when the user wats to write a new value)
- //function declared as: cdecl void ConvertBackRoutine(int i, PTR_UINT address, unsigned char *output);
- ConvertBackRoutine:
- //jmp dllname.functionname
- //or manual:
- [64-bit]
- //parameters: (64-bit)
- //ecx=input
- //rdx=address
- //r8=address of output
- //example:
- /// do no change
- ///mov [r8],ecx //place the integer at the 4 bytes pointed to by r8
- ret
- [/64-bit]
- [32-bit]
- //parameters: (32-bit)
- push ebp
- mov ebp,esp
- //[ebp+8]=input
- //[ebp+c]=address
- //[ebp+10]=address of output
- //example:
- push eax
- push ebx
- mov eax,[ebp+8] //load the value into eax
- mov ebx,[ebp+10] //load the output address into ebx
- mov [ebx],eax //write the value into the address
- pop ebx
- pop eax
- pop ebp
- ret
- [/32-bit]
- ]],cs_decimal_typeName)
- --print(script)
- registerCustomTypeAutoAssembler(script)
- --local ct = getCustomType(cs_decimal_typeName)
- --print(ct and ct.name)
Add Comment
Please, Sign In to add comment