In nortel.dll:NBsop_GetMCEKcdValues, we need to place a decoded key string like the following in the buffer passed via pointer in parameter 1: CP4: 2,1,1,20,0,0,20,0,0,0,0,1,200,0,0,0,0,10,6,3,350\0 (null terminated, I assume) 2 HW - 201IPE 1 Switch Type - Meridian 1 1 Connectivy Mechanism - Proprietary CTI 20 Voice Channels - 20 0 Fax Channels - 0 0 Speech Act. Channels - 0 20 Email by Phone Channels - 20 0 Directory Synchronization - NO 0 AppBuilder Fax Enable - NO 0 Networking Enable - NO 0 NMS Enable - NO 1 Symposium Integration - YES 200 Voice Seats - 200 0 Fax Seats - 0 0 Desktop Seats - 0 0 Speech Act. Seats - 0 0 Email by Phone Seats - 0 10 Email by Phone Languages - 10 6 Prompt Languages - 6 3 SR Languages - 3 350 Storage Hours - 350 same thing, broken up into groups of 4 chars. 0: 2,1, 4: 1,20 8: ,0,0 c: ,20, 10: 0,0, 14: 0,0, 18: 1,20 1c: 0,0, 20: 0,0, 24: 0,10 28: ,6,3 2c: ,350 30: \0\0\0\0 CP5.0.0: 2,0,1,1,20,0,0,20,0,0,0,0,1,0,0,200,0,0,0,0,10,6,3,350 2 HW - 201IPE 0 EHW - None (see HW) 1 Switch Type - Meridian 1 1 Connectivy Mechanism - Proprietary CTI 20 Voice Channels - 20 0 Fax Channels - 0 0 Speech Act. Channels - 0 20 Email by Phone Channels - 20 0 Directory Synchronization - NO 0 AppBuilder Fax Enable - NO 0 Networking Enable - NO 0 NMS Enable - NO 1 Symposium Integration - YES 0 Voice Forms - NO 0 High Availability Option - None 200 Voice Seats - 200 0 Fax Seats - 0 0 Desktop Seats - 0 0 Speech Act. Seats - 0 0 Email by Phone Seats - 0 10 Email by Phone Languages - 10 6 Prompt Languages - 6 3 SR Languages - 3 350 Storage Hours - 350 same thing, broken up into groups of 4 chars. 0: 2,0, 4: 1,1, 8: 20,0 c: ,0,2 10: 0,0, 14: 0,0, 18: 0,1, 1c: 0,0, 20: 200, 24: 0,0, 28: 0,0, 2c: 10,6 30: ,3,3 34: 50\0\0 and here is a 1006 CP5.0.0 example: 7,2,5,3,24,0,0,20,0,0,0,0,0,0,0,200,0,0,0,0,10,6,3,350 7,2,5,3,192,192,96,72,1,1,1,0,0,1,0,50000,40000,40000,40000,50000,10,6,3,2400 7 HW - Extended 2 EHW - 1006r 5 Switch Type - SL100 3 Connectivy Mechanism - T1-SMDI 192 Voice Channels - 192 192 Fax Channels - 192 96 Speech Act. Channels - 96 72 Email by Phone Channels - 72 1 Directory Synchronization - YES 1 AppBuilder Fax Enable - YES 1 Networking Enable - YES 0 NMS Enable - NO 0 Symposium Integration - NO 1 Voice Forms - YES 0 High Availability Option - None 50000 Voice Seats - 50000 40000 Fax Seats - 40000 40000 Desktop Seats - 40000 40000 Speech Act. Seats - 40000 50000 Email by Phone Seats - 50000 10 Email by Phone Languages - 10 6 Prompt Languages - 6 3 SR Languages - 3 2400 Storage Hours - 2400 00: 7,2, 04: 5,3, 08: 192, 0c: 192, 10: 96,7 14: 2,1, 18: 1,1, 1c: 0,0, 20: 1,0, 24: 5000 28: 0,40 2c: 000, 30: 4000 34: 0,40 38: 000, 3c: 5000 40: 0,10 44: ,6,3 48: ,240 4c: 0\0\0\0 The code makes some assumptions about buffer size, but I imagine the size must suffice to hold any reasonable decoding of a key. Most of the fields are fixed length, effectively, since they are 1 digit. Some of them can be a bit larger since their range can extend much higher (like storage hours and seat counts). We also need to return 0 to indicate success, I think. The simplest thing to do is just replace the function with some code like this, which loads the pointer to the string buffer into EAX and just uses a ton of mov to put the string in the buffer. Not the most efficient, but it avoids having to find a safe place to put a string. 8b 45 08 mov EAX,dword ptr [EBP + param_1] c7 40 00 32 2c 30 2c mov [EAX+0x00],#'2,0,' c7 40 04 31 2c 31 2c mov [EAX+0x04],#'1,1,' c7 40 08 32 30 2c 30 mov [EAX+0x08],#'20,0' c7 40 0c 2c 30 2c 32 mov [EAX+0x0c],#',0,2' c7 40 10 30 2c 30 2c mov [EAX+0x10],#'0,0,' c7 40 14 30 2c 30 2c mov [EAX+0x14],#'0,0,' c7 40 18 30 2c 31 2c mov [EAX+0x18],#'0,1,' c7 40 1c 30 2c 30 2c mov [EAX+0x1c],#'0,0,' c7 40 20 32 30 30 2c mov [EAX+0x20],#'200,' c7 40 24 30 2c 30 2c mov [EAX+0x24],#'0,0,' c7 40 28 30 2c 30 2c mov [EAX+0x28],#'0,0,' c7 40 2c 31 30 2c 36 mov [EAX+0x2c],#'10,6' c7 40 30 2c 33 2c 33 mov [EAX+0x30],#',3,3' c7 40 34 35 30 00 00 mov [EAX+0x34],#'50\0\0' The problem is that DLLs can and do undergo relocation at times, so we need to dodge any absolute references like these that would need to be relocated at runtime for fear of the dynamic linker clobbering our new code: 10001d9e c7 05 f0 MOV dword ptr [DAT_1000a1f0],0x0 a1 00 10 00 00 00 00 10001dbe ff 15 08 CALL dword ptr [->KERNEL32.DLL::MultiByteToWideChar] 90 00 10 That particular snippet appears to be setting a global variable. Additionally, we need to watch out for absolute jumps, calls, or branches (conditional jumps). Luckily branches are all relative on x86, and most of the jumps encountered are likely to be relative as well. Calls within the DLL are likely to be relative, but calls that go outside the DLL are indirected using absolute indices into a vector table, making them absolute references. That said, then the whole function replacement is as follows, weaving the mov instructions into the existing structure and dodging relocations: 10001d87 55 PUSH EBP ; save EBP 10001d88 8b ec MOV EBP,ESP ; setting up the stack frame, parameter 1 will be at EBP+8 10001d8a 8b 45 08 MOV EAX,dword ptr [EBP + param_1] ; get the pointer to the buf in EAX 10001d8d c7 40 00 MOV dword ptr [EAX+0x00],#'2,0,' ; start loading the buf 32 2c 30 2c 10001d94 c7 40 04 MOV dword ptr [EAX+0x04],'1,1,' 31 2c 31 2c 10001d9b eb 0b JMP EIP+0x0b ; skip over the absolute we can't touch 10001d9d 90 NOP 10001d9e c7 05 f0 MOV dword ptr [DAT_1000a1f0],0x0 a1 00 10 00 00 00 00 10001da8 c7 40 08 MOV dword ptr [EAX+0x08],'20,0' 32 30 2c 30 10001daf c7 40 0c MOV dword ptr [EAX+0x0c],',0,2' 2c 30 2c 32 10001db6 eb 0c JMP EIP+0x0c ; skip over abs ref we can't touch 10001db8 90 90 90 NOPx6 90 90 90 10001dbe ff 15 08 CALL dword ptr [->KERNEL32.DLL::MultiByteToWideChar] 90 00 10 10001dc4 c7 40 10 MOV dword ptr [EAX+0x10],'0,0,' 30 2c 30 2c 10001dcb c7 40 14 MOV dword ptr [EAX+0x14],'0,0,' 30 2c 30 2c 10001dd2 c7 40 18 MOV dword ptr [EAX+0x18],'0,1,' 30 2c 31 2c 10001dd9 c7 40 1c MOV dword ptr [EAX+0x1c],'0,0,' 30 2c 30 2c 10001de0 c7 40 20 MOV dword ptr [EAX+0x20],'200,' 32 30 30 2c 10001de7 eb 08 JMP EIP+0x08 10001de9 90 90 NOPx2 10001deb ff 15 08 CALL dword ptr [->KERNEL32.DLL::MultiByteToWideChar] 90 00 10 10001df1 c7 40 24 MOV dword ptr [EAX+0x24],'0,0,' 30 2c 30 2c 10001df8 c7 40 28 MOV dword ptr [EAX+0x28],'0,0,' 30 2c 30 2c 10001dff c7 40 2c MOV dword ptr [EAX+0x2c],'10,6' 31 30 2c 36 10001e06 c7 40 30 MOV dword ptr [EAX+0x30],',3,3' 2c 33 2c 33 10001e0d eb 09 JMP EIP+0x09 10001e0f 90 90 90 NOPx3 10001e12 ff 15 08 CALL dword ptr [->KERNEL32.DLL::MultiByteToWideChar] 90 00 10 10001e18 c7 40 34 MOV dword ptr [EAX+0x34],'50\0\0' 35 30 00 00 10001e1f c7 40 38 MOV dword ptr [EAX+0x38],'\0\0\0\0' 00 00 00 00 10001e26 c7 40 3c MOV dword ptr [EAX+0x3c],'\0\0\0\0' 00 00 00 00 10001e2d c7 40 40 MOV dword ptr [EAX+0x40],'\0\0\0\0' 00 00 00 00 10001e34 c7 40 44 MOV dword ptr [EAX+0x44],'\0\0\0\0' 00 00 00 00 10001e3b c7 40 48 MOV dword ptr [EAX+0x48],'\0\0\0\0' 00 00 00 00 10001e42 c7 40 4c MOV dword ptr [EAX+0x4c],'\0\0\0\0' 00 00 00 00 10001e49 31 c0 XOR EAX,EAX ; set return value to 0 10001e4b 8b e5 MOV ESP,EBP ; clean up the stack frame 10001e4d 5d POP EBP ; restore 10001e4e c3 RET