* Copyright (c) 2006-2008 VMware, Inc. All rights reserved.
* **********************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#include <assert.h>
#include <stdio.h>
#include <math.h>
#include <process.h>
#include "tools.h"
* test for case 7357: ensure code origins patterns disallow other code on
* page and self-modifying and cross-modified patterns
* - case 4020 scenarios:
* other code on the page
* same thread changes pattern
this was incorrectly allowed before 4020 fix
* another thread changes pattern, also allowed before 4020 fix
* pattern code itself changes pattern, also allowed before 4020 and
only fixed by 4020 due to luck
* - -trampoline_displaced_code
* - -trampoline_dirjmp
*/
00364f8d 8bff mov edi,edi
00364f8f 55 push ebp
00364f90 8bec mov ebp,esp
00364f92 e9c5835b7c jmp ntdll!LdrQueryImageFileExecutionOptions+0x5 (7c91d35c)
*/
unsigned char datacode[] = "\x8b\xff"
"\x55"
"\x8b\xec"
"\xe9\x00\x00\x00\x00"
"\x90"
"\xe9\x00\x00\x00\x00"
;
#define DATACODE_POST_JMP ((ptr_int_t)datacode + sizeof(datacode) - 1 - 6)
#define DATACODE_JMP_OPND_IDX (sizeof(datacode) - 1 - 5 - 1 - 4)
#define DATACODE_POST_2ND_JMP ((ptr_int_t)datacode + sizeof(datacode) - 1)
#define DATACODE_2ND_JMP_OPND_IDX (sizeof(datacode) - 1 - 4)
* of modifying itself.
* example of mov immed to abs addr:
0x24722535 c7 05 78 41 6d 24 b4 mov $0x151b88b4 -> 0x246d4178
88 1b 15
*/
unsigned char datacode2[] =
"\xc7\x05\x00\x00\x00\x00\x00\x00\x00\x00"
"\xe9\x00\x00\x00\x00"
;
static __declspec(naked) void image_target()
{
__asm {
jmp offset datacode
pop ebp
ret
}
}
static __declspec(naked) void image_target2()
{
__asm {
jmp offset datacode2
mov edi,edi
mov edi,edi
nop
ret
}
}
void
maliciousness()
{
static int instances = 0;
print("malicious code executing #%d!\n", ++instances);
}
int WINAPI
run_func(void *arg)
{
int offs;
offs = (ptr_int_t)&maliciousness -
((ptr_int_t)datacode + 2 + 5 );
datacode[2] = 0xe9;
*((int *)(&datacode[3])) = offs;
__asm {
pusha
call offset datacode
popa
}
}
int
main(int argc, char *argv[])
{
int offs, tid;
unsigned long hThread;
INIT();
print("testing hook pattern\n");
protect_mem(datacode, sizeof(datacode), ALLOW_READ | ALLOW_WRITE | ALLOW_EXEC);
protect_mem(datacode2, sizeof(datacode), ALLOW_READ | ALLOW_WRITE | ALLOW_EXEC);
assert((((ptr_int_t)datacode) & ~(PAGE_SIZE - 1)) ==
(((ptr_int_t)&datacode[sizeof(datacode) - 1]) & ~(PAGE_SIZE - 1)));
offs = ((ptr_int_t)&image_target + 5 ) - DATACODE_POST_JMP;
*((int *)(&datacode[DATACODE_JMP_OPND_IDX])) = offs;
__asm {
pusha
call offset datacode
popa
}
print("testing non-pattern-match on same page\n");
offs = (ptr_int_t)&maliciousness - DATACODE_POST_2ND_JMP;
*((int *)(&datacode[DATACODE_2ND_JMP_OPND_IDX])) = offs;
offs = DATACODE_POST_JMP;
__asm {
pusha
call dword ptr offs
popa
}
print("testing non-pattern-match in same region\n");
offs = (ptr_int_t)&maliciousness -
((ptr_int_t)datacode + 2 + 5 );
datacode[2] = 0xe9;
*((int *)(&datacode[3])) = offs;
__asm {
pusha
call offset datacode
popa
}
datacode[2] = 0x55;
datacode[3] = 0x8b;
datacode[4] = 0xec;
datacode[5] = 0xe9;
offs = ((ptr_int_t)&image_target + 5 ) - DATACODE_POST_JMP;
print("testing hook pattern again\n");
*((int *)(&datacode[DATACODE_JMP_OPND_IDX])) = offs;
__asm {
pusha
call offset datacode
popa
}
print("testing non-pattern-match in same region by another thread\n");
hThread = _beginthreadex(NULL, 0, run_func, NULL, 0, &tid);
WaitForSingleObject((HANDLE)hThread, INFINITE);
print("testing different pattern match in same region\n");
offs = (ptr_int_t)&maliciousness - ((ptr_int_t)datacode + 5);
datacode[0] = 0xe9;
*((int *)(&datacode[1])) = offs;
__asm {
pusha
call offset datacode
popa
}
protect_mem(datacode2, sizeof(datacode), ALLOW_READ | ALLOW_WRITE);
protect_mem(datacode2, sizeof(datacode), ALLOW_READ | ALLOW_WRITE | ALLOW_EXEC);
print("testing pattern match that modifies itself to be a non-match\n");
* shared area and we end up getting lucky.
*/
offs = ((ptr_int_t)&image_target2 + 10 ) -
((ptr_int_t)datacode2 + sizeof(datacode2) - 1);
*((int *)(&datacode2[sizeof(datacode2) - 5])) = offs;
* datacode (I would put another jmp at end of datacode2 but we'll
* just elide and allow!) which will go to maliciousness
*/
offs = (ptr_int_t)(&datacode) - ((ptr_int_t)datacode2 + sizeof(datacode2) - 1);
*((int *)(&datacode2[6])) = offs;
*((int *)(&datacode2[2])) = (ptr_int_t)&datacode2[11];
__asm {
pusha
call offset datacode2
popa
}
print("finished\n");
return 0;
}