admin管理员组文章数量:1417685
I have n Early Launch Antimalware (ELAM) capable certificate which I am using to sign a driver and my usermode application - which works just fine, however when I add some additional code to launch a child process as PPL, in EventViewer I can see:
Code Integrity is unable to verify the image integrity of the file
\Device\HarddiskVolume3\Windows\System32\fcon.dll because the set
of per-page image hashes could not be found on the system.
The target machine is a Windows 11 Virtual Machine that I'm using for driver development - I have statically linked vcruntime140.dll
into my service as that was causing some errors.
What's the deal with fcon.dll
? Windows has loaded ntdll.dll
, kernel32.dll
etc into the service just fine - given fcon.dll
is a legitimate windows DLL coming from C:\Windows\System32
why cannot it be used in the PPL service?
How can I resolve this? Seeing as I can't statically link fcon
into the binary, is this a problem with Windows? The only possible thing I can think of is making a local copy of the DLL and signing it with my PPL and loading the image into the service when it starts; but that wont account for differences between Windows versions etc where the DLL may be different. I cant be the first to have this error, but I have found surprisingly little on Google.
If it helps, here is my service binary (Rust). I do not think it is an issue with the child process, as when I invalidate the path, it still produces the error in Eventviewer
/// The service entrypoint for the binary
#[unsafe(no_mangle)]
pub unsafe extern "system" fn ServiceMain(_: u32, _: *mut PWSTR) {
// register the service with SCM (service control manager)
let h_status = match unsafe {RegisterServiceCtrlHandlerW(
PCWSTR(svc_name().as_ptr()),
Some(service_handler)
)} {
Ok(h) => h,
Err(e) => panic!("[!] Could not register service. {e}"),
};
// notify SCM that service is starting
unsafe { update_service_status(h_status, SERVICE_START_PENDING.0) };
// start the service main loop
run_service(h_status);
}
/// Main service execution loop
fn run_service(h_status: SERVICE_STATUS_HANDLE) {
unsafe {
update_service_status(h_status, SERVICE_RUNNING.0);
//
// spawn child PPL
//
// todo restart VM and try this, and so on until you get the error
let mut startup_info = STARTUPINFOEXW::default();
let mut attribute_size_list: usize = 0;
if let Err(e) = InitializeProcThreadAttributeList(
None,
1, // The count of attributes to be added to the list.
None, // This parameter is reserved and must be zero.
&mut attribute_size_list) {
panic!("Error calling InitializeProcThreadAttributeList. {e}");
}
if attribute_size_list == 0 {
panic!("Attribute size list should not be 0. Win32 error code: {}", GetLastError().0);
}
let mut attribute_list_mem = vec![0u8; attribute_size_list];
startup_info.lpAttributeList = LPPROC_THREAD_ATTRIBUTE_LIST(attribute_list_mem.as_mut_ptr() as *mut _);
if let Err(e) = InitializeProcThreadAttributeList(
Some(startup_info.lpAttributeList),
1, // The count of attributes to be added to the list.
None, // This parameter is reserved and must be zero.
&mut attribute_size_list) {
panic!("Error calling InitializeProcThreadAttributeList after attribute list initialised. {e}");
}
// update protection level to be the same as the PPL service
let mut protection_level = PROTECTION_LEVEL_SAME;
if let Err(e) = UpdateProcThreadAttribute(
startup_info.lpAttributeList,
0,
PROC_THREAD_ATTRIBUTE_PROTECTION_LEVEL as _,
Some(&mut protection_level as *mut _ as *mut _),
size_of_val(&protection_level),
None,
None,
) {
panic!("[!] Could not update protection level for child process. {e}");
}
// start the process
let mut process_info = PROCESS_INFORMATION::default();
// todo update this
let path: Vec<u16> = r"C:\Users\flux\AppData\Roaming\Svc\etw_consumer.exe"
.encode_utf16()
.chain(std::iter::once(0))
.collect();
if let Err(e) = CreateProcessW(
PCWSTR(path.as_ptr()),
None,
None,
None,
false,
EXTENDED_STARTUPINFO_PRESENT | CREATE_PROTECTED_PROCESS,
None,
PCWSTR::null(),
&mut startup_info.StartupInfo as *mut _ as *const _,
&mut process_info
) {
panic!("[!] Could not create child process. {e}");
}
// Main loop
while !SERVICE_STOP.load(Ordering::SeqCst) {
sleep(Duration::from_secs(1));
}
update_service_status(h_status, SERVICE_STOPPED.0);
}
}
fn svc_name() -> Vec<u16> {
let mut svc_name: Vec<u16> = vec![];
"ppl_runner".encode_utf16().for_each(|c| svc_name.push(c));
svc_name.push(0);
svc_name
}
/// Handles service control events (e.g., stop)
unsafe extern "system" fn service_handler(control: u32) {
match control {
SERVICE_CONTROL_STOP => {
SERVICE_STOP.store(true, Ordering::SeqCst);
}
_ => {}
}
}
/// Update the service status in the SCM
unsafe fn update_service_status(h_status: SERVICE_STATUS_HANDLE, state: u32) {
let mut service_status = SERVICE_STATUS {
dwServiceType: SERVICE_WIN32_OWN_PROCESS,
dwCurrentState: SERVICE_STATUS_CURRENT_STATE(state),
dwControlsAccepted: if state == SERVICE_RUNNING.0 { 1 } else { 0 },
dwWin32ExitCode: ERROR_SUCCESS.0,
dwServiceSpecificExitCode: 0,
dwCheckPoint: 0,
dwWaitHint: 0,
};
unsafe {let _ = SetServiceStatus(h_status, &mut service_status); }
}
fn main() {
let mut service_name: Vec<u16> = "PPLRunner\0".encode_utf16().collect();
let service_table = [
SERVICE_TABLE_ENTRYW {
lpServiceName: PWSTR(service_name.as_mut_ptr()),
lpServiceProc: Some(ServiceMain),
},
SERVICE_TABLE_ENTRYW::default(),
];
unsafe {
StartServiceCtrlDispatcherW(service_table.as_ptr()).unwrap();
}
}
I have n Early Launch Antimalware (ELAM) capable certificate which I am using to sign a driver and my usermode application - which works just fine, however when I add some additional code to launch a child process as PPL, in EventViewer I can see:
Code Integrity is unable to verify the image integrity of the file
\Device\HarddiskVolume3\Windows\System32\fcon.dll because the set
of per-page image hashes could not be found on the system.
The target machine is a Windows 11 Virtual Machine that I'm using for driver development - I have statically linked vcruntime140.dll
into my service as that was causing some errors.
What's the deal with fcon.dll
? Windows has loaded ntdll.dll
, kernel32.dll
etc into the service just fine - given fcon.dll
is a legitimate windows DLL coming from C:\Windows\System32
why cannot it be used in the PPL service?
How can I resolve this? Seeing as I can't statically link fcon
into the binary, is this a problem with Windows? The only possible thing I can think of is making a local copy of the DLL and signing it with my PPL and loading the image into the service when it starts; but that wont account for differences between Windows versions etc where the DLL may be different. I cant be the first to have this error, but I have found surprisingly little on Google.
If it helps, here is my service binary (Rust). I do not think it is an issue with the child process, as when I invalidate the path, it still produces the error in Eventviewer
/// The service entrypoint for the binary
#[unsafe(no_mangle)]
pub unsafe extern "system" fn ServiceMain(_: u32, _: *mut PWSTR) {
// register the service with SCM (service control manager)
let h_status = match unsafe {RegisterServiceCtrlHandlerW(
PCWSTR(svc_name().as_ptr()),
Some(service_handler)
)} {
Ok(h) => h,
Err(e) => panic!("[!] Could not register service. {e}"),
};
// notify SCM that service is starting
unsafe { update_service_status(h_status, SERVICE_START_PENDING.0) };
// start the service main loop
run_service(h_status);
}
/// Main service execution loop
fn run_service(h_status: SERVICE_STATUS_HANDLE) {
unsafe {
update_service_status(h_status, SERVICE_RUNNING.0);
//
// spawn child PPL
//
// todo restart VM and try this, and so on until you get the error
let mut startup_info = STARTUPINFOEXW::default();
let mut attribute_size_list: usize = 0;
if let Err(e) = InitializeProcThreadAttributeList(
None,
1, // The count of attributes to be added to the list.
None, // This parameter is reserved and must be zero.
&mut attribute_size_list) {
panic!("Error calling InitializeProcThreadAttributeList. {e}");
}
if attribute_size_list == 0 {
panic!("Attribute size list should not be 0. Win32 error code: {}", GetLastError().0);
}
let mut attribute_list_mem = vec![0u8; attribute_size_list];
startup_info.lpAttributeList = LPPROC_THREAD_ATTRIBUTE_LIST(attribute_list_mem.as_mut_ptr() as *mut _);
if let Err(e) = InitializeProcThreadAttributeList(
Some(startup_info.lpAttributeList),
1, // The count of attributes to be added to the list.
None, // This parameter is reserved and must be zero.
&mut attribute_size_list) {
panic!("Error calling InitializeProcThreadAttributeList after attribute list initialised. {e}");
}
// update protection level to be the same as the PPL service
let mut protection_level = PROTECTION_LEVEL_SAME;
if let Err(e) = UpdateProcThreadAttribute(
startup_info.lpAttributeList,
0,
PROC_THREAD_ATTRIBUTE_PROTECTION_LEVEL as _,
Some(&mut protection_level as *mut _ as *mut _),
size_of_val(&protection_level),
None,
None,
) {
panic!("[!] Could not update protection level for child process. {e}");
}
// start the process
let mut process_info = PROCESS_INFORMATION::default();
// todo update this
let path: Vec<u16> = r"C:\Users\flux\AppData\Roaming\Svc\etw_consumer.exe"
.encode_utf16()
.chain(std::iter::once(0))
.collect();
if let Err(e) = CreateProcessW(
PCWSTR(path.as_ptr()),
None,
None,
None,
false,
EXTENDED_STARTUPINFO_PRESENT | CREATE_PROTECTED_PROCESS,
None,
PCWSTR::null(),
&mut startup_info.StartupInfo as *mut _ as *const _,
&mut process_info
) {
panic!("[!] Could not create child process. {e}");
}
// Main loop
while !SERVICE_STOP.load(Ordering::SeqCst) {
sleep(Duration::from_secs(1));
}
update_service_status(h_status, SERVICE_STOPPED.0);
}
}
fn svc_name() -> Vec<u16> {
let mut svc_name: Vec<u16> = vec![];
"ppl_runner".encode_utf16().for_each(|c| svc_name.push(c));
svc_name.push(0);
svc_name
}
/// Handles service control events (e.g., stop)
unsafe extern "system" fn service_handler(control: u32) {
match control {
SERVICE_CONTROL_STOP => {
SERVICE_STOP.store(true, Ordering::SeqCst);
}
_ => {}
}
}
/// Update the service status in the SCM
unsafe fn update_service_status(h_status: SERVICE_STATUS_HANDLE, state: u32) {
let mut service_status = SERVICE_STATUS {
dwServiceType: SERVICE_WIN32_OWN_PROCESS,
dwCurrentState: SERVICE_STATUS_CURRENT_STATE(state),
dwControlsAccepted: if state == SERVICE_RUNNING.0 { 1 } else { 0 },
dwWin32ExitCode: ERROR_SUCCESS.0,
dwServiceSpecificExitCode: 0,
dwCheckPoint: 0,
dwWaitHint: 0,
};
unsafe {let _ = SetServiceStatus(h_status, &mut service_status); }
}
fn main() {
let mut service_name: Vec<u16> = "PPLRunner\0".encode_utf16().collect();
let service_table = [
SERVICE_TABLE_ENTRYW {
lpServiceName: PWSTR(service_name.as_mut_ptr()),
lpServiceProc: Some(ServiceMain),
},
SERVICE_TABLE_ENTRYW::default(),
];
unsafe {
StartServiceCtrlDispatcherW(service_table.as_ptr()).unwrap();
}
}
Share
Improve this question
asked Jan 31 at 7:49
letters_and_numbersletters_and_numbers
131 silver badge4 bronze badges
2
|
1 Answer
Reset to default 0As per Luke's response in the comments, fcon.dll
does not include pagehashes in its signature.
On investigation, this DLL is required by the panic!()
macro, so removing this prevents the error.
本文标签: Windows PPL Service will not runCode Integrity error with a Windows System32 DLLStack Overflow
版权声明:本文标题:Windows PPL Service will not run - Code Integrity error with a Windows System32 DLL - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745275895a2651183.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
signtool verify /v /a /ph c:\windows\system32\fcon.dll
. Nothing you can do about this, but perhaps you can figure out why this DLL is being loaded in the first place? Seems like a strange one. – Luke Commented Jan 31 at 10:52