<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>my tech blog &#187; Microsoft</title>
	<atom:link href="http://billauer.se/blog/category/microsoft/feed/" rel="self" type="application/rss+xml" />
	<link>https://billauer.se/blog</link>
	<description>Anything I found worthy to write down.</description>
	<lastBuildDate>Thu, 12 Mar 2026 11:36:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.2</generator>
		<item>
		<title>Microsoft Windows: Atomic ops and memory barriers</title>
		<link>https://billauer.se/blog/2021/05/windows-atomic-memory-fences/</link>
		<comments>https://billauer.se/blog/2021/05/windows-atomic-memory-fences/#comments</comments>
		<pubDate>Thu, 13 May 2021 16:01:44 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Windows device drivers]]></category>

		<guid isPermaLink="false">https://billauer.se/blog/?p=6326</guid>
		<description><![CDATA[Introduction This post examines what the Microsoft&#8217;s compiler does in response to a variety of special functions that implement atomic operations and memory barriers. If you program like a civilized human being, that is with spinlocks and mutexes, this is a lot of things you should never need to care about. I&#8217;ve written a similar [...]]]></description>
			<content:encoded><![CDATA[<h3>Introduction</h3>
<p>This post examines what the Microsoft&#8217;s compiler does in response to a variety of special functions that implement atomic operations and memory barriers. If you program like a civilized human being, that is with spinlocks and mutexes, this is a lot of things you should never need to care about.</p>
<p>I&#8217;ve written a <a href="https://billauer.se/blog/2014/08/wmb-rmb-mmiomb-effects/" target="_blank">similar post regarding Linux</a>, and it&#8217;s recommended to read it before this one (even though it repeats some of the stuff here).</p>
<p>To make a long story short:</p>
<ul>
<li>The Interlocked-something functions do not just guarantee atomicity, but also function as a memory barrier to the compiler</li>
<li>Memory fences are unnecessary for the sake of synchronizing between processors</li>
<li>The conclusion is hence that those Interlocked functions also work as multiprocessor memory barriers.</li>
</ul>
<h3>Trying it out</h3>
<p>The following code:</p>
<pre>LONG atomic_thingy;

__declspec(noinline) LONG do_it(LONG *p) {
  LONG x = 0;
  LONG y;
  x += *p;
  y = InterlockedExchangeAdd(&amp;atomic_thingy, 0x1234);
  x += *p;

  return x + y;
}</pre>
<p>When compiling this as &#8220;free&#8221; (i.e. optimized), this yields:</p>
<pre>_do_it@4:
  00000000: 8B FF              mov         edi,edi
  00000002: 55                 push        ebp
  00000003: 8B EC              mov         ebp,esp
  00000005: 8B 45 08           mov         eax,dword ptr [ebp+8]
  00000008: 8B 10              <strong>mov         edx,dword ptr [eax]</strong>
  0000000A: 56                 push        esi
  0000000B: B9 34 12 00 00     mov         ecx,1234h
  00000010: BE 00 00 00 00     mov         esi,offset _atomic_thingy
  00000015: F0 0F C1 0E        <strong>lock xadd   dword ptr [esi],ecx</strong>
  00000019: 8B 00              <strong>mov         eax,dword ptr [eax]</strong>
  0000001B: 03 C1              add         eax,ecx
  0000001D: 03 C2              add         eax,edx
  0000001F: 5E                 pop         esi
  00000020: 5D                 pop         ebp
  00000021: C2 04 00           ret         4</pre>
<p>First thing to note is that InterlockedExchangeAdd() has been translated into a &#8220;LOCK XADD&#8221;, which indeed fetches the previous value into ECX and stores the updated value into memory. The previous value is stored in ECX after this operation, which is @y in the C code &#8212; InterlockedExchangeAdd() returns the previous value.</p>
<p>XADD by itself isn&#8217;t atomic, which is why the LOCK prefix is added. More about LOCK below.</p>
<p>What is crucially important to note, is that putting InterlockedExchangeAdd() between the two reads of *p prevents the optimizations of these two reads into one. @p isn&#8217;t defined as volatile, and yet it&#8217;s read from twice (ptr [eax]).</p>
<p>Another variant, now trying  InterlockedOr():</p>
<pre>LONG atomic;

__declspec(noinline) LONG do_it(LONG *p) {
  LONG x = 0;
  LONG y;
  x += *p;
  y = InterlockedOr(&amp;atomic, 0x1234);
  x += *p;

  return x + y;
}</pre>
<p>Once again, compiled as &#8220;free&#8221;, turns into this:</p>
<pre>_do_it@4:
  00000000: 8B FF              mov         edi,edi
  00000002: 55                 push        ebp
  00000003: 8B EC              mov         ebp,esp
  00000005: 8B 4D 08           mov         ecx,dword ptr [ebp+8]
  00000008: 8B 11              <strong>mov         edx,dword ptr [ecx]</strong>
  0000000A: 53                 push        ebx
  0000000B: 56                 push        esi
  0000000C: 57                 push        edi
  0000000D: BE 34 12 00 00     mov         esi,1234h
  00000012: BF 00 00 00 00     mov         edi,offset _atomic
  00000017: 8B 07              mov         eax,dword ptr [edi]
  00000019: 8B D8              mov         ebx,eax
  0000001B: 0B DE              <strong>or          ebx,esi</strong>
  0000001D: F0 0F B1 1F        <strong>lock cmpxchg dword ptr [edi],ebx</strong>
  00000021: 75 F6              jne         00000019
  00000023: 8B F0              mov         esi,eax
  00000025: 8B 01              <strong>mov         eax,dword ptr [ecx]</strong>
  00000027: 5F                 pop         edi
  00000028: 03 C6              add         eax,esi
  0000002A: 5E                 pop         esi
  0000002B: 03 C2              add         eax,edx
  0000002D: 5B                 pop         ebx
  0000002E: 5D                 pop         ebp
  0000002F: C2 04 00           ret         4</pre>
<p>This is quite amazing: The OR isn&#8217;t implemented as an atomic operation, but rather it goes like this: The previous value of @atomic is fetched into EAX and then moved to EBX. It&#8217;s ORed with the constant 0x1234, and then the cmpxchg instruction writes the result (in EBX) into @atomic only if its previous value was the same as EAX. If not, the previous value is stored in EAX instead. In the latter case, the JNE loops back to try again.</p>
<p>I should mention that cmpxchg compares with EAX and stores the previous value to it if the comparison fails, even though this register isn&#8217;t mentioned explicitly in the instruction. It&#8217;s just a thing that cmpxchg works with EAX. EBX is the register to compare with, and it therefore appears in the instruction. Confusing, yes.</p>
<p>Also here, *p is read twice.</p>
<p>It&#8217;s also worth noting that using InterlockedOr() with the value 0 as a common way to grab the current value yields basically the same code (only the constant is generated with a &#8220;xor esi,esi&#8221; instead).</p>
<p>So if you want to use an Interlocked function just to read from a variable,  InterlockedExchangeAdd() with zero is probably better, because it doesn&#8217;t create all that loop code around it.</p>
<p>Another function I&#8217;d like to look at is InterlockedExchange(), as it&#8217;s used a lot. Spoiler: No surprises are expected.</p>
<pre>LONG atomic_thingy;

__declspec(noinline) LONG do_it(LONG *p) {
  LONG x = 0;
  LONG y;
  x += *p;
  y = InterlockedExchange(&amp;atomic_thingy, 0);
  x += *p;

  return x + y;
}</pre>
<p>and this is what it compiles into:</p>
<pre>_do_it@4:
  00000000: 8B FF              mov         edi,edi
  00000002: 55                 push        ebp
  00000003: 8B EC              mov         ebp,esp
  00000005: 8B 45 08           mov         eax,dword ptr [ebp+8]
  00000008: 8B 10              <strong>mov         edx,dword ptr [eax]</strong>
  0000000A: 56                 push        esi
  0000000B: 33 C9              xor         ecx,ecx
  0000000D: BE 00 00 00 00     mov         esi,offset _atomic_thingy
  00000012: 87 0E              <strong>xchg        ecx,dword ptr [esi]</strong>
  00000014: 8B 00              <strong>mov         eax,dword ptr [eax]</strong>
  00000016: 03 C1              add         eax,ecx
  00000018: 03 C2              add         eax,edx
  0000001A: 5E                 pop         esi
  0000001B: 5D                 pop         ebp
  0000001C: C2 04 00           ret         4</pre>
<p>And finally, what about writing twice to the same place?</p>
<pre>LONG atomic_thingy;

__declspec(noinline) LONG do_it(LONG *p) {
  LONG y;
  *p = 0;
  y = InterlockedExchangeAdd(&amp;atomic_thingy, 0);
  *p = 0;

  return y;
}</pre>
<p>Writing the same constant value twice to a non-volatile variable. This calls for an optimization. But the Interlocked function prevents it, as expected:</p>
<pre>_do_it@4:
  00000000: 8B FF              mov         edi,edi
  00000002: 55                 push        ebp
  00000003: 8B EC              mov         ebp,esp
  00000005: 8B 4D 08           mov         ecx,dword ptr [ebp+8]
  00000008: 83 21 00           <strong>and         dword ptr [ecx],0</strong>
  0000000B: 33 C0              xor         eax,eax
  0000000D: BA 00 00 00 00     mov         edx,offset _atomic_thingy
  00000012: F0 0F C1 02        <strong>lock xadd   dword ptr [edx],eax</strong>
  00000016: 83 21 00           <strong>and         dword ptr [ecx],0</strong>
  00000019: 5D                 pop         ebp
  0000001A: C2 04 00           ret         4</pre>
<p>Writing a zero is implemented by ANDing with zero, so it&#8217;s a bit confusing. But it&#8217;s done twice, before and after the &#8220;lock xadd&#8221;. Needless to say, these two writes are fused into one by the compiler without the Interlocked statement in the middle (I&#8217;ve verified it with disassembly, 32 and 64 bit).</p>
<h3>Volatile?</h3>
<p>In Microsoft&#8217;s <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-interlockedexchangeadd" target="_blank">definition for the InterlockedExchangeAdd() function</a> (and all other similar ones) is that the first operand is a pointer to a LONG volatile. Why volatile? Does the variable really need to be?</p>
<p>The answer is no, if all accesses to the variable is made with Interlocked-something functions. There will be no compiler optimizations, not on the call itself, and the call itself is a compiler memory barrier.</p>
<p>And it&#8217;s a good habit to stick to these functions, because of this implicit compiler memory barrier: That&#8217;s usually what we want and need, even if we&#8217;re not fully aware of it. Accessing a shared variable almost always has a &#8220;before&#8221; and &#8220;after&#8221; thinking around it. The volatile keyword doesn&#8217;t protect against reordering optimizations by the compiler (or otherwise).</p>
<p>But if the variable is accessed without these functions in some places, the volatile keyword should definitely be used when defining that variable.</p>
<h3>More about LOCK</h3>
<p>It&#8217;s a prefix that is added to an instruction in order to ensure that it&#8217;s performed atomically. In many cases, it&#8217;s superfluous and sometimes ignored, as the atomic operation is ensured anyhow.</p>
<p>From Intel&#8217;s <a href="https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf" target="_blank">64 and IA-32 Architectures Software Developer’s Manual, Volume 2 (instruction set reference)</a> vol. 2A page 3-537, on the &#8220;LOCK&#8221; prefix for instructions:</p>
<blockquote><p><em>Causes the processor’s LOCK# signal to be asserted during execution of the accompanying instruction (turns the instruction into an atomic instruction). In a multiprocessor environment, the LOCK# signal ensures that the processor has exclusive use of any shared memory while the signal is asserted.</em></p></blockquote>
<p>The manual elaborates further on the LOCK prefix, but says nothing about memory barriers / fences. This is implemented with the MFENCE, SFENCE and LFENCE instructions.</p>
<p>The LOCK prefix is encoded with an 0xf0 coming before the instruction in the binary code, by the way.</p>
<h3>Linux counterparts</h3>
<p>For x86 only, of course:</p>
<ul>
<li>atomic_set() turns into a plain &#8220;mov&#8221;</li>
<li>atomic_add() turns into &#8220;lock add&#8221;</li>
<li>atomic_sub() turns into &#8220;lock sub&#8221;</li>
</ul>
<div>I&#8217;m not sure that there are any Windows functions for exactly these.</div>
<h3>Is a memory barrier (fences) required?</h3>
<p>Spoiler: Not in x86 kernel code, including 32 and 64 bits. Surprise. Unless you really yearn for a headache, this is the right place to stop reading this post.</p>
<p>The theoretical problem is that each processor core might reorder the storing or fetching of data between registers, cache and memory in any possible way to increase performance. So if one one processor writes to X and then Y, and it&#8217;s crucial that the other processor sees the change in Y only when it also sees X updated, a memory barrier is often used. In the Linux kernel,  smp_wmb() and smp_rbm() are used in conjunction to ensure this.</p>
<p>For example, if X is some data buffer, and Y is a flag saying that the data is valid. One processor fills the buffer X and then sets Y to &#8220;valid&#8221;. The other processor reads Y first, and if it&#8217;s valid, it accesses the buffer X. But what if the other processor sees Y as valid before it sees the data in X correctly? A store memory barrier before writing to Y <strong>and</strong> a read memory barrier before reading from X ensures this.</p>
<p>The thing is, that the Linux kernel&#8217;s implementation of smp_wmb() and smp_rbm() for x86 <a href="https://billauer.se/blog/2014/08/wmb-rmb-mmiomb-effects/" target="_blank">is a NOP</a>. Note that it&#8217;s only the smp_*() versions that are NOPs. The non-smp fences turn into opcodes that implement fences. Assuming that the Linux guys know what they&#8217;re doing (which is a pretty safe assumption in this respect) they&#8217;re telling us that the view of ordering is kept intact across processor cores. In other words, if I can assure that X is written before Y on one processor, then Intel promises me that on another processor X will be read with the updated value before Y is seen updated.</p>
<p>Looking at how Microsoft&#8217;s examples solve certain multithreading issues, it&#8217;s quite evident that they trust the processor to retain the ordering of operations.</p>
<p>Memory fences are hence only necessary to ensure the ordering on a certain processor on x86. On <a href="https://en.wikipedia.org/wiki/Memory_ordering" target="_blank">different architectures </a>(e.g. ARM v7) smp_wmb() and smp_rbm() actually do produce some code.</p>
<p>When are these fences really needed? From Intel&#8217;s <a href="https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf" target="_blank">64 and IA-32 Architectures Software Developer’s Manual, Volume 2 (instruction set reference)</a> vol. 2A page 4-22, on the &#8220;MFENCE&#8221; instruction:</p>
<blockquote><p><em>Performs a serializing operation on all load-from-memory and store-to-memory instructions that were issued prior the MFENCE instruction. This serializing operation guarantees that every load and store instruction that precedes the MFENCE instruction in program order becomes globally visible before any load or store instruction that follows the MFENCE instruction. The MFENCE instruction is ordered with respect to all load and store instructions, other MFENCE instructions, any LFENCE and SFENCE instructions, and any serializing instructions (such as the CPUID instruction).</em></p></blockquote>
<p>That didn&#8217;t answer much. I searched for fence instructions in the disassembly of a <strong>Linux</strong> kernel compiled for x86_64. A lot of fence instructions are used in the initial CPU bringup, in particular after setting CPU registers. Makes sense. Then there are several other fence instructions in drivers, which aren&#8217;t necessarily needed, but who has the guts to remove them?</p>
<p>Most interesting is where I <strong>didn&#8217;t</strong> find a single fence instruction: In any of the object files generated in kernel/locking/. In other words, Linux&#8217; mutexes and spinlocks are all implemented without any fence. So this is most likely a good proof that they aren&#8217;t needed for anything else but things related to the CPU state itself. I guess. For a 64-bit x86, that is.</p>
<p>Going back to Microsoft, it&#8217;s interesting that their docs for userspace Interlocked functions say &#8220;This function generates a full memory barrier (or fence) to ensure that memory operations are completed in order&#8221;, but not those for kernel space. Compare, for example <a href="https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedor" target="_blank">InterlockedOr() for applications</a> vs. <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-interlockedor" target="_blank">the same function for kernel</a>. Truth is I didn&#8217;t bother to do the same disassembly test for application code.</p>
<h3>Some barriers functions</h3>
<p>(or: A collection of functions you probably don&#8217;t need, even if you think you do)</p>
<ul>
<li>KeFlushWriteBuffer(): Undocumented and <a href="http://www.osronline.com/article.cfm%5Eid=80.htm" target="_blank">rarely mentioned</a>, intended for <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/_kernel/#core-kernel-library-support-routines" target="_blank">internal kernel use</a>. Probably just makes sure that the cache has been flushed (?).</li>
<li><a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-kememorybarrier" target="_blank">KeMemoryBarrier</a>():  Calls _KeMemoryBarrier(). But in wdm.h, there&#8217;s an implementation of  this function, calling FastFence() and LoadFence(). But these are just  macros for __faststorefence and _mm_lfence. Looked at next.</li>
<li>_mm_lfence() : Turns into an lfence opcode. Same as rmb() in Linux.</li>
<li>_mm_sfence(): Turns into an sfence opcode. Same as wmb() in Linux.</li>
<li>_mm_mfence(): Turns into an mfence opcode.</li>
</ul>
<p>I&#8217;ve verified that the _mm_*fence() builtins generated the said  opcodes when compiled for x86 and amd64 alike. See some experiments on  this matter below.</p>
<p>The <a href="https://docs.microsoft.com/en-us/cpp/intrinsics/writebarrier?view=msvc-160" target="_blank">deprecated</a> _ReadBarrier(),  _WriteBarrier() and  _ReadWriteBarrier() produce no  code at all.  MemoryBarrier() ends up as a call to _MemoryBarrier().</p>
<h3>Experimenting with fence instructions</h3>
<p>(or: A major waste of time)</p>
<p>This is the code compiled:</p>
<pre>__declspec(noinline) LONG do_it(LONG *p) {
  LONG x = 0;
  x += *p;
  _mm_lfence();
  x += *p;

  return x;
}</pre>
<p>With a &#8220;checked compiation&#8221; this turns into:</p>
<pre>_do_it@4:
  00000000: 8B FF              mov         edi,edi
  00000002: 55                 push        ebp
  00000003: 8B EC              mov         ebp,esp
  00000005: 51                 push        ecx
  00000006: C7 45 FC 00 00 00  mov         dword ptr [ebp-4],0
            00
  0000000D: 8B 45 08           mov         eax,dword ptr [ebp+8]
  00000010: 8B 4D FC           mov         ecx,dword ptr [ebp-4]
  00000013: 03 08              add         ecx,dword ptr [eax]
  00000015: 89 4D FC           mov         dword ptr [ebp-4],ecx
  00000018: 0F AE E8           lfence
  0000001B: 8B 55 08           mov         edx,dword ptr [ebp+8]
  0000001E: 8B 45 FC           mov         eax,dword ptr [ebp-4]
  00000021: 03 02              add         eax,dword ptr [edx]
  00000023: 89 45 FC           mov         dword ptr [ebp-4],eax
  00000026: 8B 45 FC           mov         eax,dword ptr [ebp-4]
  00000029: 8B E5              mov         esp,ebp
  0000002B: 5D                 pop         ebp
  0000002C: C2 04 00           ret         4</pre>
<p>OK, this is too much. There is no ptimization at all. So let&#8217;s look at the &#8220;free&#8221; compilation instead:</p>
<pre>_do_it@4:
  00000000: 8B FF              mov         edi,edi
  00000002: 55                 push        ebp
  00000003: 8B EC              mov         ebp,esp
  00000005: 8B 45 08           mov         eax,dword ptr [ebp+8]
  00000008: 8B 08              <strong>mov         ecx,dword ptr [eax]</strong>
  0000000A: 0F AE E8           <strong>lfence</strong>
  0000000D: 8B 00              <strong>mov         eax,dword ptr [eax]</strong>
  0000000F: 03 C1              add         <strong>eax,ecx</strong>
  00000011: 5D                 pop         ebp
  00000012: C2 04 00           ret         4</pre>
<p>So clearly, the fence command made the compiler read the value from memory twice, as opposed to optimizing the second read away. Note that there&#8217;s no volatile keyword involved.  So  except for the fence, there&#8217;s no reason to read from *p twice.</p>
<p>The exact same result is obtained with _mm_mfence().</p>
<p>Trying with _mm_sfence() yields an interesting result however:</p>
<pre>_do_it@4:
  00000000: 8B FF              mov         edi,edi
  00000002: 55                 push        ebp
  00000003: 8B EC              mov         ebp,esp
  00000005: 8B 45 08           mov         eax,dword ptr [ebp+8]
  00000008: 8B 00              mov         eax,dword ptr [eax]
  0000000A: 0F AE F8           <strong>sfence</strong>
  0000000D: 03 C0              <strong>add         eax,eax</strong>
  0000000F: 5D                 pop         ebp
  00000010: C2 04 00           ret         4</pre>
<p>*p is read into eax once, then the fence, and then  it&#8217;s added by itself. As opposed to above, where it was read into eax  before the fence, then read again into ecx, and then added eax with ecx.</p>
<p>So the compiler felt free to optimize the two reads into one, because the store fence deals only with writes into memory, not reads. Given that there&#8217;s no volatile keyword used, it&#8217;s fine to optimize reads, which is exactly what it did.</p>
<p>The same optimization occurs if the fence command is removed completely, of course.</p>
<p>For the record, I&#8217;ve verified the equivalent behavior on the amd64 target (I&#8217;ll spare you the assembly code).</p>
]]></content:encoded>
			<wfw:commentRss>https://billauer.se/blog/2021/05/windows-atomic-memory-fences/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows trusting many more Root Authorities than certmgr shows</title>
		<link>https://billauer.se/blog/2021/05/microsoft-certificate-manager-root-certs/</link>
		<comments>https://billauer.se/blog/2021/05/microsoft-certificate-manager-root-certs/#comments</comments>
		<pubDate>Thu, 13 May 2021 09:41:38 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[crypto]]></category>
		<category><![CDATA[Microsoft]]></category>

		<guid isPermaLink="false">https://billauer.se/blog/?p=6315</guid>
		<description><![CDATA[This baffled me for a while: I used certmgr to see if a Windows 10 machine had a root certificate that was needed to certify a certain digital signature, and it wasn&#8217;t listed. But then the signature was validated. And not only that, the root certificate was suddenly present in certmgr. Huh? Here&#8217;s a quick [...]]]></description>
			<content:encoded><![CDATA[<p>This baffled me for a while: I used certmgr to see if a Windows 10 machine  had a root certificate that was needed to certify a certain digital signature, and it wasn&#8217;t listed. But then the signature was validated. And not only that, the root certificate was suddenly present in certmgr. Huh?</p>
<p>Here&#8217;s a quick demonstration. This is the &#8220;before&#8221; screenshot of the Certificate Manager window (click to enlarge):</p>
<p><a href="https://billauer.se/blog/wp-content/uploads/2021/05/certmgr-before.png"><img class="aligncenter size-medium wp-image-6316" title="Windows Certificate Manager before examining .cab file" src="https://billauer.se/blog/wp-content/uploads/2021/05/certmgr-before-300x189.png" alt="Windows Certificate Manager before examining .cab file" width="300" height="189" /></a></p>
<p>Looking at the registry, I found 11 certificates in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates\AuthRoot\Certificates\ and 12 certificates in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates\ROOT\Certificates\, so it matches exactly certmgr&#8217;s view of 23 root certificates.</p>
<p>And so I had a .cab file with a certificate that requires Certum&#8217;s root certificate for validation. Clear from the screenshot above, it&#8217;s not installed.</p>
<p>Then I right-clicked that .cab file, selected Properties, then the &#8220;Digital Signature Tab&#8221;, selected the certificate and clicked Details, and boom! A new root certificate was automatically installed (click to enlarge):</p>
<p><a href="https://billauer.se/blog/wp-content/uploads/2021/05/certmgr-after.png"><img class="aligncenter size-medium wp-image-6317" title="Windows Certificate Manager after examining .cab file" src="https://billauer.se/blog/wp-content/uploads/2021/05/certmgr-after-300x190.png" alt="Windows Certificate Manager after examining .cab file" width="300" height="190" /></a></p>
<p>And suddenly there are 12 certificates in the AuthRoot part of the registry instead of 11. Magic.</p>
<p>And here&#8217;s the behind the scenes of that trick.</p>
<p>Microsoft publishes a Certificate Trust List (CTL), which every computer downloads automatially every now and then (once a week, typically). It contains the list of root authorities that the computer should trust, however apparently they are imported into the registry only as needed. <a href="https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/dn265983(v=ws.11)" target="_blank">This page</a> describes the concept of CTL in general.</p>
<p>I don&#8217;t know where this is stored on the disk, however one can download the list and create an .sst file, which opens certmgr when double-clicked. That lists all certificates of the downloaded CTL. 425 of them, as of May 2021, including Certum of course:</p>
<pre>&gt; certutil -generateSSTFromWU auth.sst</pre>
<p>So it seems like Windows installs certificates from the CRL as necessary to validate certificate chains. This includes the GUI for examining certificates, verifying with signtool, as well as requiring the certificate for something actually useful.</p>
<p>There&#8217;s also a utility called CTLInfo out there, which I haven&#8217;t tried. It apparently displays the CTL currently loaded in the system, but I haven&#8217;t tried it out.</p>
<p>There&#8217;s <a href="https://security.stackexchange.com/questions/108951/how-much-of-a-problem-is-it-that-windows-hides-some-of-the-trusted-root-ca-cer" target="_blank">another post in Stackexchange</a> on this matter.</p>
<p>Besides, I&#8217;ve written <a title="A sledge hammer introduction to X.509 certificates" href="https://billauer.se/blog/2021/04/certificate-ca-tutorial-primer/" target="_blank">a general post on certificates</a>, if all this sounded like Chinese.</p>
]]></content:encoded>
			<wfw:commentRss>https://billauer.se/blog/2021/05/microsoft-certificate-manager-root-certs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Attestation signing of Windows device driver: An unofficial guide</title>
		<link>https://billauer.se/blog/2021/05/windows-drivers-attestation-signing/</link>
		<comments>https://billauer.se/blog/2021/05/windows-drivers-attestation-signing/#comments</comments>
		<pubDate>Tue, 11 May 2021 13:32:39 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[crypto]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Windows device drivers]]></category>

		<guid isPermaLink="false">https://billauer.se/blog/?p=6296</guid>
		<description><![CDATA[Introduction This is my best effort to summarize the steps to attestation signing for Windows drivers (see Microsoft&#8217;s main page on this). I&#8217;m mostly a Linux guy with no connections inside Microsoft, so everything written below is based upon public sources, trial and (a lot of) error, some reverse engineering, and speculations. This couldn&#8217;t be [...]]]></description>
			<content:encoded><![CDATA[<h3>Introduction</h3>
<p>This is my best effort to summarize the steps to attestation signing for Windows drivers (see <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/dashboard/attestation-signing-a-kernel-driver-for-public-release" target="_blank">Microsoft&#8217;s main page on this</a>). I&#8217;m mostly a Linux guy with no connections inside Microsoft, so everything written below is based upon public sources, trial and (a lot of) error, some reverse engineering, and speculations. This couldn&#8217;t be further away from the horse&#8217;s mouth, and I may definitely be wrong occasionally (that is, more than usual).</p>
<p>Also, the whole topic of attestation signature seems to be changing all the time, so it&#8217;s important to keep in mind that this reflects the situation of May 10th 2021. Please comment below as things change or whenever I got things wrong to begin with.</p>
<p>Attestation signing replaces the method that was available until April 2021, which was signing the driver locally by its author, just like any code signing. With attestation signing, Microsoft&#8217;s own digital signature is used to sign the driver. To achieve that, the driver&#8217;s .inf and .sys files are packed in a .cab file, signed by the author, and submitted to Microsoft. Typically 10 minutes later, the driver is signed by Microsoft, and can be downloaded back by the author.</p>
<p>Unfortunately, the signature obtained this way is recognized by Windows 10 only. In order to obtain a signature that works with Windows 7 and 8, the driver needs to get through an <a href="https://en.wikipedia.org/wiki/Windows_Hardware_Lab_Kit" target="_blank">HLK test</a>.</p>
<h3>Signing up to the Hardware Program</h3>
<p>This seemingly simple first step can be quite confusing and daunting, so let&#8217;s begin with the most important point: The only piece of information that I found present in Microsoft&#8217;s output (i.e. their signature add-ons), which wasn&#8217;t about Microsoft itself, was the company&#8217;s name, as I stated during the enrollment. In other words, what happens during the sign-up process doesn&#8217;t matter so much, as long as it&#8217;s completed.</p>
<p><a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/dashboard/attestation-signing-a-kernel-driver-for-public-release" target="_blank">This</a> is Microsoft&#8217;s general how-to page for attestation signing in general, and <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/dashboard/register-for-the-hardware-program" target="_blank">this one</a> about joining the hardware program. It wasn&#8217;t clear to me from these what I was supposed to do, so I&#8217;ll try to offer some hints.</p>
<p>The subscription to the Hardware Program can begin when two conditions are met:</p>
<ul>
<li> You have the capability to sign a file with an Extended Validation (EV) code signing certificate.</li>
<li>You have an Azure Active Directory Domain Services managed domain (&#8220;Azure AD&#8221;).</li>
</ul>
<p>Obtaining an EV certificate is a bureaucratic process, and it&#8217;s not cheap. But at least the other side tells you what to do, once you&#8217;ve paid. I went for <a href="https://www.ssl.com/" target="_blank">ssl.com</a> as their price was lowest, and working with them I got the impression that the company has hired people who actually know what they do. <del>In short, recommended.</del> Actually, <a title="The eSigner fraud: ssl.com charging my credit card arbitrarily with hundreds of dollars" href="https://billauer.se/blog/2021/11/esigner-cloud-signing-ssl-com-certificate/" target="_blank">read this first</a> if you plan working with them.</p>
<p>So what&#8217;s the Domain Services thing? Well, this is the explanation from inside the Partner web interface (once it has already been set up): &#8220;Partner Center uses Azure Active Directory for identity and access management&#8221;. That&#8217;s the best I managed to find on why this is necessary.</p>
<p>For a single user scenario, this boils down to obtaining a domain name like <em>something</em><span class="dirPickerDomain">.onmicrosoft.com from Microsoft. It doesn&#8217;t matter if the name turns out long and daunting: It doesn&#8217;t appear anywhere else, and you&#8217;re not going to type it manually.<br />
</span></p>
<p>So here&#8217;s what to do: First thing first, <a href="https://login.microsoftonline.com" target="_blank">create a fresh</a> Microsoft account. Not really necessary if you already have one, but there&#8217;s going to be quite some mail going its way (some of which is promotional, unless you&#8217;re good at opting out).</p>
<p>Being logged into that account, start off on Azure&#8217;s <a href="https://azure.microsoft.com/" target="_blank">main page</a>. Join the 12-month free trial. It&#8217;s free, and yet you&#8217;ll need to supply a valid credit card number in the process. As of writing this, I don&#8217;t know what happens after 12 months (but see &#8220;Emails from Azure calling for an upgrade&#8221; below on developments).</p>
<p>The next step is to create that domain service. I believe <a href="https://docs.microsoft.com/en-us/azure/active-directory-domain-services/tutorial-create-instance" target="_blank">this is Microsoft&#8217;s page on the topic</a>, and this is the moment one wonders why there&#8217;s talk about DNSes and virtual networks. Remember that the only goal is to obtain the domain name, not to actually use it.</p>
<p>And here comes the fuzzy part, where I&#8217;m not sure I didn&#8217;t waste time with useless operations. So you may try following this, as it worked for me. But I can&#8217;t say I understand why these seemingly pointless actions did any good. I suspect that the bullets in italics below can be skipped &#8212; maybe it&#8217;s just about creating an Azure account, and not necessarily allocate resources?</p>
<p>So here are the steps that got me going:</p>
<ul>
<li>Log in to your (new?) Azure account.</li>
<li>Go to <a href="https://portal.azure.com/" target="_blank">Azure&#8217;s Portal</a> (or click the &#8220;Portal&#8221; link at the top bar on Azure&#8217;s <a href="https://azure.microsoft.com/" target="_blank">main page</a>)</li>
</ul>
<div>Maybe skip these steps (?):</div>
<ul>
<li><span style="color: #888888;"><em>Click &#8220;Create a resource&#8221; (at the top left) and pick Azure AD Domain Services.</em></span></li>
<li><span style="color: #888888;"><em>For Resource Group I created a new one, &#8220;the_resource_group&#8221;. I guess the name doesn&#8217;t matter.</em></span></li>
<li><span style="color: #888888;"><em>The DNS name doesn&#8217;t matter, apparently.  yourcompany.onmicrosoft.com or something. It&#8217;s not going to appear anywhere.</em></span></li>
<li><span style="color: #888888;"><em>I set SKU set to Standard, as it appeared to be the least expensive one.</em></span></li>
<li><span style="color: #888888;"><em>After finishing the setup, it took about an hour for Azure to finish the configuration. Time for a long and well deserved coffee break.</em></span></li>
<li><span style="color: #888888;"><em>But then it complained that I need to set up DNSes or something. So I went along with the automatic fix.</em></span></li>
</ul>
<p>(end of possibly useless steps)</p>
<ul>
<li>There&#8217;s this thing on the <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/dashboard/register-for-the-hardware-program" target="_blank">Register for the Hardware Program page</a> saying that one should log in with the Global administrator account. <a href="https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/active-directory-whatis" target="_blank">This page</a> defines Azure AD Global administrator as &#8220;This administrator role is automatically assigned to whomever created the Azure AD tenant&#8221;. So apparently for a fresh Azure account, it&#8217;s OK as is.</li>
<li>At this point, you&#8217;re hopefully set to <a href="https://partner.microsoft.com/en-us/dashboard/Registration/Hardware" target="_blank">register</a> to the Hardware Developer Program. After clicking &#8220;Next&#8221; on the landing page, you&#8217;ll be given the choice of &#8220;Sign in to Azure AD&#8221; or &#8220;Create a new directory for free&#8221;. The Azure AD is already set up, so log in with the account just created.</li>
<li>A word about that &#8220;Create a new directory for free&#8221; option. To make things even more confusing, this appears to be a quick  and painless shortcut, however in my case I got &#8220;This domain name is not  available&#8221; for any domain name I tried with. Maybe I missed something,  but this was a dead end for me. <a href="https://partner.microsoft.com/en-us/dashboard/Registration/Tenant/CreateTenant" target="_blank">This</a> is the page I didn&#8217;t manage to get through. Maybe your luck is better than mine. So this is why I created the Azure AD first, and then went for registration.</li>
<li>Going on with the registration, you&#8217;re given a file to sign with your EV certificate. I got a .bin file, but in fact it  had  .exe or .sys format. So it can be renamed to .exe and used with cloud signature services (I used <a href="https://express.esigner.com/">eSigner</a>). BUT do this only if you&#8217;re going to sign the .cab files with the same machinery, or you&#8217;ll waste a few hours wondering what&#8217;s going on. Or read below (&#8220;When the signature isn&#8217;t validated&#8221;) why it was wrong in my case.</li>
<li>And this is the really odd thing: Inside the Microsoft Partner Center, clicking the &#8220;your account&#8221; button (at the top right) it shows the default directory in use. At some point during the enrollment procedure, the link with the Azure AD I created was made (?), but for some reason, the default directory shown was  something like microsoftazuremycompany.onmicrosoft.com instead of mycompany.onmicrosoft.com, which is the domain I created before. This didn’t stop me from signing  a driver. So if another directory was used, why did I create one earlier?</li>
</ul>
<p>After all this, I was set to submit drivers for signature: From this moment on, the entry point for signing drivers is the <a href="https://partner.microsoft.com/en-us/dashboard/" target="_blank">Microsoft Partner Center dashboard&#8217;s main page</a>.</p>
<h3>Emails from Azure calling for an upgrade</h3>
<p>To make a long story short, quite a few emails arrived on behalf of  Microsoft Azure, urging me to &#8220;upgrade&#8221; my account, i.e. to allow  charging my credit card for Azure services. I ignored them all, and had  no issues continuing to sign drivers.</p>
<p>And now to the details.</p>
<p>A day after signing up to Azure, I discovered that $20 had been  reduced from my promotional free trial credit. Apparently, I had enabled  stuff that would have cost real money. So I deleted the resources I had  allocated in Azure. This includes deleting the  mycompany.onmicrosoft.com domain, which was obviously ignored by the  Partner Center. It was about deleting the the resource group (which  contained 7 elements, with the domain included): Just clicking on the  resource group in the main portal page, and then Delete Resource Group  at the top. It took several minutes for Azure to digest that.</p>
<p>About a month later, I got a notification from Azure urging me to upgrade my account: It went</p>
<blockquote><p>You’re receiving this email because your free credit has  expired. Because of this, your Azure subscription and services have been  disabled. To restore your services, upgrade to pay-as-you-go pricing.</p></blockquote>
<p>Scary, heh? Does &#8220;services have been disabled&#8221; mean that I&#8217;m about to lose the ability to sign drivers?</p>
<p>Once again, &#8220;upgrade&#8221; is a cute expression for giving permission to  charge the credit card that I had to give during submission. The details  of which can&#8217;t be deleted from the account, unless I submit another,  valid one, instead.</p>
<p>As a side note, it turned out that I had a Network Watcher group  activated. Maybe I missed it earlier, and maybe it was somehow added. So  I deleted it as well. But it’s not clear if this was related to the  fact that the credits expired, whatever that means.</p>
<p>A few days on, another mail from Azure, basically the same, urging me  to upgrade. One day after that, came an invoice. How come? I haven&#8217;t  approved any payment. So it was an invoice on 0.00 USD. Zero. Why it was  sent to me, is still unclear.</p>
<p>And finally, roughly two months after the initial subscription, I got  a &#8220;We’re sorry to see you go&#8221; email from Azure, saying &#8220;Your free  credit expired on (this and this date), and because of this we’ve  deleted your subscription and any associated data and services&#8221;. Uhhm.  What about driver signing? Well, I&#8217;ve spoiled the suspension above.</p>
<p>Two weeks after getting this last email, I deleted all cookies on my  browser that were related to Microsoft, logged into my account at  the Partner Center and submitted a driver for signature. The process  went through smoothly.</p>
<p>Checking my Azure cloud account, it seemed to had been reset to its  starting state, even with a suggestion to start another $200 free trial  credit round. Detaching my credit card was however still impossible.</p>
<p>So apparently, there&#8217;s no problem just ignoring these emails, and continue signing forever. Emphasis on &#8220;apparently&#8221;.</p>
<h3>Overview of the signature process</h3>
<p>To make a long story short, you prepare a .cab file with the driver&#8217;s files, sign it with your EV Certificate, upload it to the Hardware Dashboard, and get it back after 10 minutes with Microsoft&#8217;s digital signatures all over the place.</p>
<p>So instead of signing the driver yourself, you pack the whole thing neatly, and send it to Microsoft for adding the .cat file and signing the drivers. And yet, you must sign the .cab file to prove that you&#8217;re the one taking responsibility for it. It&#8217;s Microsoft&#8217;s signature on the driver in the end, but they know who to bash if something goes wrong.</p>
<p>.cab files are exactly like .zip files, in the sense that they contain a directory tree, not just a bunch of files. Unfortunately, when looking at .cab files with Windows&#8217; built-in utilities, the directory  structure isn&#8217;t presented, and it looks like a heap of files. This holds true both when double clicking a .cab file and when using expand -D, from Windows XP all the way to Windows 10. Ironically enough, double-clicking a .cab file with Linux desktop GUI opens it correctly as a directory tree.</p>
<p>It&#8217;s important to consider .cab files like .zip, with hierarchy, because the way the driver is submitted is by organizing the files in directories <strong>exactly as they appear in the driver package for release</strong>, minus the .cat file. So what really happens is that Microsoft uncompresses the .cab file like a .zip, adds the .cat file and then performs the digital signing. It then compresses it all back into a .zip file and returns it back to you. The files remain in the same positions all through.</p>
<p>I guess the only reason .zip files aren&#8217;t uploaded instead of .cab, is that signtool doesn&#8217;t sign zips.</p>
<p>Some people out there, who missed this point, got the impression that the signing is done for each architecture separately. That&#8217;s possible, but there&#8217;s no reason to go that way. It&#8217;s just a matter of preparing the file hierarchy properly.</p>
<h3>Preparing the .cab file</h3>
<p>For reference, this is Microsoft&#8217;s <a href="https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/makecab" target="_blank">short page on makecab</a> and  <a href="https://docs.microsoft.com/en-us/previous-versions/bb417343(v=msdn.10)?redirectedfrom=MSDN#microsoftmakecabusersguide" target="_blank">very long page</a> on .cab files (which begins with cabarc, but goes on with makecab).</p>
<p>First, set up a .ddf file, looking something like this:</p>
<pre>.Set CabinetFileCountThreshold=0
.Set FolderFileCountThreshold=0
.Set FolderSizeThreshold=0
.Set MaxCabinetSize=0
.Set MaxDiskFileCount=0
.Set MaxDiskSize=0
.Set CompressionType=MSZIP
.Set Cabinet=on
.Set Compress=on

;Specify file name for new cab file
.Set CabinetNameTemplate=thedriver.cab
.Set DiskDirectoryTemplate= ; Output .cab files into current directory

.Define pathtodriver=thedriver-dir

.Set DestinationDir=thedriver
%pathtodriver%\thedriver.inf
.Set DestinationDir=thedriver\i386
%pathtodriver%\i386\thedriver.sys
.Set DestinationDir=thedriver\amd64
%pathtodriver%\amd64\thedriver.sys</pre>
<p>The .cab file is then generated with something like</p>
<pre>&gt; makecab /f thedriver.ddf</pre>
<p>&#8220;makecab&#8221; is in Window&#8217;s execution path by default.</p>
<p>In my case of transitioning from self-signed drivers to attestation signature, there was already a script that generated the directory ready for releasing the driver. So the change I made was not to copy the .cat file into that directory, and instead of signing the .cat file, create a .cab.</p>
<p>The .ddf file above relates to a driver released for  Intel architecture, 32 and 64 bits. The subdirectories in the driver package are i386 and amd64, respectively, as defined in the .inf file.</p>
<p>Changes you should make to the .ddf file:</p>
<ul>
<li>Replace all &#8220;thedriver&#8221; with the name of your driver (i.e. the name of the .inf and .sys files).</li>
<li>Set &#8220;pathtodriver&#8221; to where the driver package is. Note that makecab&#8217;s /d flag allows setting variables, so the Define directive can be removed, and instead go something like
<pre>&gt; makecab /d pathtodriver=..\driverpackage thedriver.ddf</pre>
</li>
<li>Then possibly modify the files to be included. Each DestinationDir assignment tells makecab the directory position to place the file(s) that appear after it. This should match the structure of your release package&#8217;s directory structure.</li>
<li>If the line doesn&#8217;t start with a dot, it&#8217;s the path to a file to copy into the .cab file. The path can be absolute (yuck) or relative to the current directory.</li>
</ul>
<p>All in all, the important thing is to form a directory tree of a driver for release in the .cab file.</p>
<p>The .ddf file shown above is a working example, and it includes only the .inf and .sys files. Including a .cat file is pointless, as Microsoft&#8217;s signature machinery generates one of its own.</p>
<p>As for .pdb files, it&#8217;s a bit more confusing: Microsoft&#8217;s <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/dashboard/attestation-signing-a-kernel-driver-for-public-release" target="_blank">main page</a> includes .pdb files in the list of &#8220;typical CAB file submissions&#8221; (actually, .cat it listed too there), and then these files don&#8217;t appear in the .ddf file example on the same page. The graphics showing a tree for multiple package submissions is inconsistent with both.</p>
<p>A .pdb files contains the symbol map of the related .sys file, allowing the kernel debugger to display meaningful stack traces and disassemblies, in particular when analyzing a bugcheck. These files are not included in a driver release, not mentioned in the .inf file, not referenced in the .cat file and are therefore unrelated to the signature of the driver. Technically, Microsoft doesn&#8217;t need these files to complete an attestation signature.</p>
<p>Microsoft nevertheless encourages submitters of drivers to include .pdb files. When these file are missing in a driver submission, a popup shows up in the web interface saying &#8220;This submission does not include symbols. It is recommended to upload symbols within each driver folder&#8221;. This however doesn&#8217;t stop the process, and not even delay it, in case you&#8217;re slow on confirming it. So it&#8217;s up to you if you want to include .pdb&#8217;s.</p>
<h3>Submitting the .cab file</h3>
<p>The command for signing the .cab file is:</p>
<pre>&gt; signtool.exe sign /fd sha256 thedriver.cab</pre>
<p>Note that timestamping is not required, but won&#8217;t hurt. The whole idea with timestamping is to make the signature valid after the certificates expire, but the .cab file is examined soon after the signature is made, and after that it has no more importance.</p>
<p>Note that ssl.com also offers an <a href="https://express.esigner.com/" target="_blank">eSigner tool</a> for signing the .cab file with a simple web interface. Just be sure to have registered with a signature made in eSigner as well, or things will go bad, see &#8220;When the signature isn&#8217;t validated&#8221; below. Or add eSigner&#8217;s certificate to the existing subscription.</p>
<p><em><strong>November 2021 update</strong>: You probably don&#8217;t want to use eSigner at all. See <a title="The eSigner fraud: ssl.com charging my credit card arbitrarily with hundreds of dollars" href="https://billauer.se/blog/2021/11/esigner-cloud-signing-ssl-com-certificate/" target="_blank">this post.</a></em></p>
<p>Then the submission itself:</p>
<ul>
<li>In <a href="https://partner.microsoft.com/en-us/dashboard/" target="_blank">Microsoft Partner Center&#8217;s dashboard</a>, click at &#8220;Drivers&#8221; on the left menubar. It might be necessary to click &#8220;Hardware&#8221; first to make this item appear.</li>
<li>Click the <strong>&#8220;Submit new hardware&#8221;</strong> button at the top left to get started.</li>
<li>Give the submission a name &#8212; it&#8217;s used just for your own reference, and surely won&#8217;t appear in the signed driver package.</li>
<li>Drag the signed cab file to where it says to.</li>
<li>The web interface requires selecting Windows releases in a lot of checkboxes. More on this just below.</li>
<li>Click &#8220;Submit&#8221; to start the machinery. Once it finishes, successfully or not, it sends a notification mail (actually, three identical mails or so. Not clear why not only one).</li>
<li>If and when the entire process is completed successfully, the driver can be downloaded: Under &#8220;Packages and signing properties&#8221;, there&#8217;s a &#8220;More&#8221; link. Click it, and a button saying &#8220;Download signed files&#8221; appears. So click it, obviously.</li>
</ul>
<p>Now to the part about selecting Windows versions. It’s an array of checkboxes. This is a screenshot of this stage (click to enlarge):</p>
<p><a href="https://billauer.se/blog/wp-content/uploads/2021/05/select-windows-releases.png"><img class="aligncenter size-medium wp-image-6343" title="Selecting OS targets for Attestation Signing " src="https://billauer.se/blog/wp-content/uploads/2021/05/select-windows-releases-300x227.png" alt="Selecting OS targets for Attestation Signing " width="300" height="227" /></a></p>
<p>First, the easy part: <strong>Don’t</strong> check the two at the top saying “Perform test-signing for X”. It says “Leave all checkboxes blank for Attestation Signing” in fine print above these.</p>
<p>Now we’re left with a whole lot of Windows 10 release numbers and  architectures. From a pure technical point of view, there’s no need for this  information to perform the signature, since the .inf file contains the  information of which architectures are targeted.</p>
<p>Rather, this is the &#8220;attestation&#8221; part: Just above the &#8220;Submit&#8221; button, it says  “You have completed quality testing of your driver for each of the  Operating Systems selected above”. So this is where <strong>you testify which platforms you&#8217;ve tested the driver with</strong>. The deal is that instead of going through the via dolorosa of HLK tests, Microsoft signs the driver for you in exchange to this testimony. Or should I say, attestation.</p>
<p>Just to spell it out: The signature can&#8217;t and doesn’t  limit itself to specific operating system builds, and it would be  insane doing so, as it wouldn’t cover future Windows releases.</p>
<p>I have to admit that in the beginning I misunderstood this part, and tried to select as much as possible. And because my driver wasn&#8217;t compiled for arm64, and I had clicked versions saying “ARM64″, the submission was rejected with “thedriver.inf  does not have NTARM64 decorated model sections” (in UniversalLog.txt). It was bit of a computer game to check the right boxes and avoid the wrong ones.</p>
<p>So no need to be greedy. Common sense is to test the driver on one operating system release for each architecture. In the example above, it&#8217;s for a driver released for Intel architecture, 32 and 64 bits. The checkbox selection reflects testing it with Windows 10 release 1607, 32- and 64-bit architecture. This is the proper way to go.</p>
<p>And yet, for the heck of it I tried submitting the same driver package with a single OS checked (1607 x64). To my surprise, the package was accepted and signed despite my declaration that it <strong>hadn&#8217;t</strong> been tested for the 32-bit version, even though a .sys file for that architecture was part of the package.</p>
<p>All in all, there must be a match between the  architectures targeted by the driver (as listed in the .inf file) and  those inferred by the selection of OSes. Nevertheless, it seems like Microsoft lets you get away with not testing all of them. In short, checking just one checkbox may be enough, even if the driver supports multiple architectures.</p>
<h3>Looking at the signed zip</h3>
<p>After receiving back the signed driver, I examined the files. My findings were:</p>
<ul>
<li>The .inf file is left completely intact (bytewise identical to the one in the .cab file).</li>
<li>A signed .cat file was added.</li>
<li>All .sys files were signed as well (contrary to what most of us do when releasing drivers). This makes the driver eligible for inclusion during boot.</li>
</ul>
<p>Looking at the digital signatures with an <a href="https://billauer.se/blog/2021/05/crypto-jots-on-asn-1-and-microsofts-cat-files/" target="_blank">ASN.1 dump utility</a>, it&#8217;s appears like the only place there&#8217;s something not pointing at Microsoft, is an non-standard <a href="https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-oshared/91755632-4b0d-44ca-89a9-9699afbbd268" target="_blank">spcSpOpusInfo</a> entry in the crypto blob, where the company&#8217;s name, appears in wide char format in the programName field (no, I&#8217;m not mistaken). This appears to be taken from the &#8220;Publisher display name&#8221; as it appears in the Account Settings in the Microsoft Partner Center dashboard.</p>
<p>So all in all, there are almost no traces to the fact that the driver&#8217;s origin isn&#8217;t Microsoft. Except for that entry in the crypto blob, which is most likely invisible unless the signature is analyzed as an ASN.1 file or string searched (with a tool that detects wide char strings). So it appears like all information, except for that &#8220;Publisher display name&#8221; remains between you and Microsoft.</p>
<h3>When the signature isn&#8217;t validated</h3>
<p>Sometimes, the process fails at the &#8220;Preparation&#8221; stage. As always on failures, the web interface suggest downloading a &#8220;full error report&#8221;. That report is a file named UniversalLog.txt file. If it says just &#8220;SignatureValidationFailed&#8221;, something went wrong with the signature validation.</p>
<p>The solution for this is to make sure that the certificate that was used for signing the .cab file is registered: Within Microsoft Partner Center, click the gear icon at the top right, select &#8220;Account Settings&#8221; and pick &#8220;Manage Certificates&#8221; at the left menu bar. That&#8217;s where the relevant certificate should be listed. The first time I got to this page, I saw the same certificate twice, and deleted one of those.</p>
<p>In my case the problem was that during the registration, I had made the signature with the cloud app (eSigner), but signed the driver with a local USB key dongle. As it turned out, these have different certificates.</p>
<p>So the solution was to delete the registered certificate from the account, and register the new one by signing a file with the local USB dongle. Doing this is a good idea in any case, because if something is wrong with the signature produced by signtool, it will fail the registration as well. So whether this renewed registration succeeds or fails, it brings you closer to the solution.</p>
<h3>Sample certificate chains</h3>
<p>For reference, these are examples of certificate chains: One properly signed .cab file and one for a the .cat file that has been attestation signed my Microsoft.</p>
<p>Note the /pa flag, meaning Default Authenticode Verification Policy is used. Or else verification may fail. Also note that the file isn&#8217;t timestamped, which is OK for submission of attestation signing.</p>
<pre>&gt; signtool verify /pa /v thefile.cab

Verifying: thefile.cab

Signature Index: 0 (Primary Signature)
Hash of file (sha256): 388D7AFB058FEAE3AEA48A2E712BCEFEB8F749F107C62ED7A41A131507891BD9

Signing Certificate Chain:
    Issued to: Certum Trusted Network CA
    Issued by: Certum Trusted Network CA
    Expires:   Mon Dec 31 05:07:37 2029
    SHA1 hash: 07E032E020B72C3F192F0628A2593A19A70F069E

        Issued to: SSL.com EV Root Certification Authority RSA R2
        Issued by: Certum Trusted Network CA
        Expires:   Mon Sep 11 02:28:20 2023
        SHA1 hash: 893E994B9C43100155AE310F34D8CC962096AE12

            Issued to: SSL.com EV Code Signing Intermediate CA RSA R3
            Issued by: SSL.com EV Root Certification Authority RSA R2
            Expires:   Wed Mar 22 10:44:23 2034
            SHA1 hash: D2953DBA95086FEB5805BEFC41283CA64C397DF5

                Issued to: THE COMPANY LTD
                Issued by: SSL.com EV Code Signing Intermediate CA RSA R3
                Expires:   Fri May 03 13:09:33 2024
                SHA1 hash: C15A6A7986AE67F1AE4B996C99F3A43F98029A54

File is not timestamped.

Successfully verified: thefile.cab

Number of files successfully Verified: 1
Number of warnings: 0
Number of errors: 0</pre>
<p>One possibly confusing situation is to check if the root certificate exists <strong>before ever </strong>running this verification on a fresh Windows installation. It may not be there, but then the verification is successful, and the root certificate appears from nowhere.  That rare situation is explained <a href="https://billauer.se/blog/2021/05/microsoft-certificate-manager-root-certs/" target="_blank">in this post</a>.</p>
<p>Next up is the attestation signed .cat file:</p>
<pre>&gt; <strong>signtool.exe verify /kp /v thedriver.cat</strong>

Verifying: thedriver.cat

Signature Index: 0 (Primary Signature)
Hash of file (sha256): ED5231781724DEA1C8DE2B1C97AC55922F4F85736132B36660FE375B44C42370

Signing Certificate Chain:
    Issued to: <strong>Microsoft Root Certificate Authority 2010</strong>
    Issued by: <strong>Microsoft Root Certificate Authority 2010</strong>
    Expires:   Sat Jun 23 15:04:01 2035
    SHA1 hash: 3B1EFD3A66EA28B16697394703A72CA340A05BD5

        Issued to: Microsoft Windows Third Party Component CA 2014
        Issued by: Microsoft Root Certificate Authority 2010
        Expires:   Mon Oct 15 13:41:27 2029
        SHA1 hash: 1906DCF62629B563252C826FDD874EFCEB6856C6

            Issued to: Microsoft Windows Hardware Compatibility Publisher
            Issued by: Microsoft Windows Third Party Component CA 2014
            Expires:   Thu Dec 02 15:25:28 2021
            SHA1 hash: 984E03B613E8C2AE9C692F0DB2C031BF3EE3A0FA

The signature is timestamped: Mon May 10 03:10:15 2021
Timestamp Verified by:
    Issued to: Microsoft Root Certificate Authority 2010
    Issued by: Microsoft Root Certificate Authority 2010
    Expires:   Sat Jun 23 15:04:01 2035
    SHA1 hash: 3B1EFD3A66EA28B16697394703A72CA340A05BD5

        Issued to: Microsoft Time-Stamp PCA 2010
        Issued by: Microsoft Root Certificate Authority 2010
        Expires:   Tue Jul 01 14:46:55 2025
        SHA1 hash: 2AA752FE64C49ABE82913C463529CF10FF2F04EE

            Issued to: Microsoft Time-Stamp Service
            Issued by: Microsoft Time-Stamp PCA 2010
            Expires:   Wed Jan 12 10:28:27 2022
            SHA1 hash: AAE5BF29B50AAB88A1072BCE770BBE40F55A9503

Cross Certificate Chain:
    Issued to: Microsoft Root Certificate Authority 2010
    Issued by: Microsoft Root Certificate Authority 2010
    Expires:   Sat Jun 23 15:04:01 2035
    SHA1 hash: 3B1EFD3A66EA28B16697394703A72CA340A05BD5

        Issued to: Microsoft Windows Third Party Component CA 2014
        Issued by: Microsoft Root Certificate Authority 2010
        Expires:   Mon Oct 15 13:41:27 2029
        SHA1 hash: 1906DCF62629B563252C826FDD874EFCEB6856C6

            Issued to: Microsoft Windows Hardware Compatibility Publisher
            Issued by: Microsoft Windows Third Party Component CA 2014
            Expires:   Thu Dec 02 15:25:28 2021
            SHA1 hash: 984E03B613E8C2AE9C692F0DB2C031BF3EE3A0FA

Successfully verified: thedriver.cat

Number of files successfully Verified: 1
Number of warnings: 0
Number of errors: 0</pre>
<p>Doing the same with the .sys file yields exactly the same result, with slight and meaningless differences in the timestamp.</p>
<p>Clearly, the certificate chain ends with &#8220;Microsoft Root Certificate Authority 2010&#8243; rather than the well-known  &#8220;Microsoft Code Verification Root&#8221;, which is the reason the attestation signature isn&#8217;t recognized by Windows 7 and 8.</p>
<p>Microsoft as a Certificate Authority, approving itself all through the chain. It&#8217;s quite odd this happened only now.</p>
]]></content:encoded>
			<wfw:commentRss>https://billauer.se/blog/2021/05/windows-drivers-attestation-signing/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Linux Wine jots</title>
		<link>https://billauer.se/blog/2020/06/linux-wine/</link>
		<comments>https://billauer.se/blog/2020/06/linux-wine/#comments</comments>
		<pubDate>Thu, 11 Jun 2020 04:16:26 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Microsoft]]></category>

		<guid isPermaLink="false">https://billauer.se/blog/?p=6051</guid>
		<description><![CDATA[General These are just a few jots on Wine. I guess this post will evolve over time. I&#8217;m running Wine version 4.0 on Linux Mint 19, running on an x86_64. First run Every time Wine is run on a blank (or absent) directory given by WINEPREFIX, it installs a Windows environment. Which Windows version an [...]]]></description>
			<content:encoded><![CDATA[<h3>General</h3>
<p>These are just a few jots on Wine. I guess this post will evolve over time.</p>
<p>I&#8217;m running Wine version 4.0 on Linux Mint 19, running on an x86_64.</p>
<h3>First run</h3>
<p>Every time Wine is run on a blank (or absent) directory given by WINEPREFIX, it installs a Windows environment. Which Windows version an several other attributes can be set with Wine Configuration:</p>
<pre>$ WINEPREFIX=/path/to/winedir /opt/wine-stable/bin/winecfg</pre>
<p>Note that Wine installs a 64-bit environment by default. Add WINEARCH=win32 after the WINEPREFIX setting on the first run of Wine for the relevant directory to install a 32-bit environment instead, which is recommended for its better support unless 64-bit applications are going to be used. No need for WINEARCH afterwards.</p>
<p>It often suggests to install Wine Mono and Wine Gecko. I usually tend to agree.</p>
<p>This installation downloads three files into .cache/wine/:  wine_gecko-2.47-x86_64.msi, wine_gecko-2.47-x86.msi  and  wine-mono-4.7.5.msi. This is why Wine doesn&#8217;t ask for permission to install these when setting up new Windows environments after the first time.</p>
<h3>Install and use Winetricks</h3>
<p>It&#8217;s a good idea in general, and it allows installation of Microsoft runtime environment easily:</p>
<pre># apt install winetricks
# apt install wine32-development</pre>
<p>And now to install Virtual Studio 6 runtime environment, for example  (solving some error message on not being able to import isskin.dll or  isskinu.dll)</p>
<pre>$ WINEPREFIX=/path/to/winedir winetricks vcrun6sp6</pre>
<p>For a list of all packages available, go</p>
<pre>$ WINEPREFIX=/path/to/winedir winetricks list-all | less</pre>
<h3>Prevent browser popup</h3>
<p>Wine has this thing that it opens a browser when so requested by the  Windows application. That can be annoying at times, and get the program  stuck when run inside a firejail. To prevent this altogether, just  delete two files:</p>
<ul>
<li>drive_c/windows/syswow64/winebrowser.exe</li>
<li>drive_c/windows/system32/winebrowser.exe</li>
</ul>
<p>but that didn&#8217;t work with Picasa, because it opened the browser through its own xdg-open located at /opt/picasa/bin/xdg-utils-1.0.2/scripts/xdg-open. So I replaced it with the following lame script</p>
<pre>#!/bin/bash
/usr/bin/konqueror "$1"</pre>
<p>so at least it doesn&#8217;t mix in the real browser (which caused a mess at times).</p>
<h3>Open explorer</h3>
<p>The simplest way to start: Open the file explorer:</p>
<pre>$ WINEPREFIX=/path/to/winedir /opt/wine-stable/bin/wine explorer</pre>
<h3>DOS command line</h3>
<pre>$ WINEPREFIX=/path/to/winedir /opt/wine-stable/bin/wine cmd</pre>
<p>This is better than expected: The command session is done directly in the console (no new window opened). Like invoking a shell.</p>
<div>
<h3>Use with firejail</h3>
<p>Windows equals viruses, and Wine doesn&#8217;t offer any protection against that. Since the entire filesystem is accessible from Z: (more on that below), it&#8217;s a good idea to run Wine from within a firejail mini-container. I have a <a href="https://billauer.se/blog/2020/06/firejail-cgroups/" target="_blank">separate post</a> on firejail.</p>
<p>The execution of the program then looks something like (non-root user):</p>
<pre>$ firejail --profile=~/my.profile --env=WINEPREFIX=/path/to/winedir /opt/wine-stable/bin/wine 'C:\Program Files\Malsoft\Malsoft.exe' &amp;</pre>
<p>The my.profile file depends on what the Windows program is expected to do. I discuss that briefly in <a href="https://billauer.se/blog/2020/06/firejail-cgroups/" target="_blank">that post</a>, however this is something that worked for me:</p>
<pre>include /etc/firejail/disable-common.inc
include /etc/firejail/disable-passwdmgr.inc
private-tmp
private-dev

# All relevant directories are read-only by default, not /opt. So add it.
read-only /opt
#
# This whitelisting protects the entire home directory.
# .cache/wine is where the Gecko + Mono installation files are kept.
# They can't be downloaded, because of "net none" below
mkdir ~/sandboxed/
mkdir ~/.cache/wine
whitelist ~/sandboxed/
whitelist ~/.cache/wine

net none
nonewprivs
caps.drop all
noroot
# blacklist everything that can be harmed
#
blacklist /mnt
blacklist /cdrom
blacklist /media
blacklist /boot</pre>
<p>Notes:</p>
<ul>
<li>Note the &#8220;net none&#8221; part. Networking completely disabled. No access to the internet nor the local network.</li>
<li>Be sure to blacklist any system-specific mount, in particular those that are writable by the regular user. Do you have a /hugestorage mount? That one.</li>
<li>There&#8217;s a seccomp filter option that often appears in template profiles. It got a program in Wine completely stuck. It prevents certain system calls, so no doubt it adds safety, but it came in the way of something in my case.</li>
</ul>
<h3>Poor man&#8217;s sandboxing</h3>
<p>If you&#8217;re too lazy to use firejail, you can remove <strong>some</strong> access to the local storage by virtue of Wine&#8217;s file system bindings. <strong>This is worth almost nothing</strong>, but almost nothing is more than nothing.</p>
<pre>$ WINEPREFIX=/path/to/winedir /opt/wine-stable/bin/winecfg</pre>
<p>In the &#8220;Drives&#8221; tab, remove Z:, and in the Desktop Integration tab, go through each of the folders and uncheck &#8220;Link to&#8221;.</p>
<p>This <strong>doesn&#8217;t</strong> prevent a Wine-aware Windows program to accessing  the machine with plain Linux API with your user permissions just like  any Linux program, and the root directory is still visible in Windows&#8217;  file browsing utilities. Yet, simple Windows programs expect any file  system to be mapped to a drive letter, and these steps prevent that. Not much, but once again, better than nothing.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>https://billauer.se/blog/2020/06/linux-wine/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Microsoft&#8217;s outlook.com servers and the art of delivering mails to them</title>
		<link>https://billauer.se/blog/2020/04/microsoft-outlook-hotmail-smtp-spam-blacklist/</link>
		<comments>https://billauer.se/blog/2020/04/microsoft-outlook-hotmail-smtp-spam-blacklist/#comments</comments>
		<pubDate>Mon, 27 Apr 2020 10:45:03 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[email]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Server admin]]></category>

		<guid isPermaLink="false">https://billauer.se/blog/?p=6032</guid>
		<description><![CDATA[Introduction Still in 2020, it seems like Microsoft lives up to its reputation: Being arrogant, thinking that anyone in business must be a huge corporate, and in particular ending up completely ridiculous. Microsoft&#8217;s mail servers, which accept on behalf of Hotmail, MSN, Office 365, Outlook.com, or Live.com users are no exception. This also affects companies [...]]]></description>
			<content:encoded><![CDATA[<h3>Introduction</h3>
<p>Still in 2020, it seems like Microsoft lives up to its reputation: Being arrogant, thinking that anyone in business must be a huge corporate, and in particular ending up completely ridiculous. Microsoft&#8217;s mail servers, which accept on behalf of Hotmail, MSN, Office 365, Outlook.com, or Live.com users are no exception. This also affects companies and other entities which use their own domain names, but use Microsoft&#8217;s services for handling mail.</p>
<p>This post summarizes my personal experience and accumulated knowledge with delivering mail to their servers. I use a simple Linux sendmail SMTP MTA on a virtual server for handling the delivery of my own private mails as well as a very low traffic of transactional mails from a web server. All in all, it&#8217;s about 100 mails / month coming out from that server to all destinations.</p>
<p>So one server, one IP address with a perfect reputation on all open spam reputation trackers, with SPF, DKIM and DMARC records all in place properly.</p>
<p>One may ask why I&#8217;m not relying on existing mail delivery services or my ISP. Answer is simple: Any commercial mail delivery server is likely to have its reputation contaminated by some spammer, no matter what protection measures they take. When that happens, odds are that emails will just disappear, because the ISP has little interest in forwarding the bounce message saying that delivery failed. On a good day, they will be handling the problem quickly, and yet the sender of the lost mail won&#8217;t be aware that the correspondence is broken.</p>
<p>For this reason, it&#8217;s quite likely that small businesses will go on keeping their own, small, email delivery servers, maintaining their own reputation. So when Outlook&#8217;s servers are nasty with a single-IP server, they&#8217;re not just arrogant, but they are causing delivery issues with small to medium businesses.</p>
<h3>To do when setting up the server</h3>
<p>For starter info, go <a href="https://sendersupport.olc.protection.outlook.com/pm/services.aspx" target="_blank">here</a>. Microsoft is pretty upfront about not being friendly to new IP addresses (see <a href="https://sendersupport.olc.protection.outlook.com/pm/troubleshooting.aspx" target="_blank">troubleshooting page</a> for postmasters).</p>
<p>So it&#8217;s a very good idea to create a Microsoft account to log into their services, and then join their Smart Network Data Service (SDNS) and Junk Mail Reporting Program. <a href="https://sendersupport.olc.protection.outlook.com/snds/index.aspx" target="_blank">This is the start page</a> for both of these services.</p>
<p>SDNS allows the owner of a mail server to register its IP address range (&#8220;<a href="https://sendersupport.olc.protection.outlook.com/snds/addnetwork.aspx" target="_blank">Request Access</a>&#8220;), so its status can be monitored (<a href="https://sendersupport.olc.protection.outlook.com/snds/ipStatus.aspx" target="_blank">&#8220;View IP Status&#8221;</a>) over time. When all is fine, the IP Status page says &#8220;All of the specified IPs have normal status&#8221;, and when they don&#8217;t like this or other IP address, it&#8217;s more like this (click to enlarge):</p>
<p><a href="https://billauer.se/blog/wp-content/uploads/2020/04/blocked-ip.png"><img class="aligncenter size-medium wp-image-6033" title="Microsoft SDNS blocked IP" src="https://billauer.se/blog/wp-content/uploads/2020/04/blocked-ip-300x96.png" alt="Microsoft SDNS blocked IP" width="300" height="96" /></a></p>
<p>The Junk Mail Reporting Program (JMRP) allows the owner of the mail server to receive notifications (by email) when a mail message is delivered however deemed suspicious, either by an end-user (marking it as spam) or by automatic means. So it&#8217;s a good idea to create a special email address for this purpose and fill in the <a href="https://sendersupport.olc.protection.outlook.com/snds/JMRP.aspx" target="_blank">JMRP form</a>. Even for the sake of claiming that you got no complaints when contacting support later on.</p>
<p>Note that this is important for delivery of mail to any institution relies on Microsoft&#8217;s mail infrastructure. A proper IP address blacklist delisting takes you from</p>
<pre>Mar 11 20:18:23 sm-mta[5817]: x2BKIL2H005815: to=&lt;xxxxxxx@mit.edu&gt;, delay=00:00:02, xdelay=00:00:02, mailer=esmtp, pri=121914, relay=mit-edu.mail.protection.outlook.com. [104.47.42.36], dsn=5.7.606, stat=User unknown</pre>
<p>(but the bounce message indicated that it&#8217;s not an unknown user, but a blacklisted IP number) to</p>
<pre>Mar 11 21:15:12 sm-mta[6170]: x2BLF8rT006168: to=&lt;xxxxxxx@mit.edu&gt;, delay=00:00:03, xdelay=00:00:03, mailer=esmtp, pri=121915, relay=mit-edu.mail.protection.outlook.com. [104.47.42.36], dsn=2.0.0, stat=Sent (&lt;5C86CFDC.6000206@example.com&gt; [InternalId=11420318042095, Hostname=DM5PR01MB2345.prod.exchangelabs.com] 11012 bytes in 0.191, 56.057 KB/sec Queued mail for delivery)</pre>
<p>Note that the session response said nothing about a blacklisted IP, however the bounce message (not shown here) did.</p>
<p>Finally, Microsoft suggest getting a certification from <a href="https://returnpath.com/solutions/email-deliverability-optimization/ip-certification/" target="_blank">Return Path</a>. A paid-for service, clearly intended for large companies and in particular mass mailers to get their spam delivered. Microsoftish irony at its best.</p>
<h3>To do when things go wrong</h3>
<p>First thing first, read the bounce message. If it says that it&#8217;s on Microsoft&#8217;s IP blacklist, go to the  <a href="https://sender.office.com/" target="_blank">Office 365 Anti-Spam IP Delist Portal</a> and delist it.</p>
<p>Then check the <a href="https://sendersupport.olc.protection.outlook.com/snds/ipStatus.aspx" target="_blank">IP&#8217;s status</a> (requires logging in). If you&#8217;re blocked, <a href="http://go.microsoft.com/fwlink/?LinkID=614866" target="_blank">contact support</a>. This doesn&#8217;t require a Microsoft login account, by the way. I&#8217;m not sure if this link to the support page is valid in the long run, so it&#8217;s on <a href="https://sendersupport.olc.protection.outlook.com/snds/index.aspx" target="_blank">SNDS&#8217; main page</a> (&#8220;contact sender support&#8221;) as well as  <a href="https://sendersupport.olc.protection.outlook.com/pm/troubleshooting.aspx" target="_blank">Troubleshooting page</a>.</p>
<h3>My own ridiculous experience</h3>
<p>I kicked off my mail server a bit more than a year ago. There was some trouble in the beginning, but that was no surprise. Then things got settled and working for a year, and only then, suddenly &amp; out of the blue, a mail to a Hotmail address bounced with:</p>
<pre>Action: failed
Status: 5.7.1
Diagnostic-Code: SMTP; 550 5.7.1 Unfortunately, messages from [193.29.56.92] weren't sent. Please contact your Internet service provider since part of their network is on our block list (S3140). You can also refer your provider to http://mail.live.com/mail/troubleshooting.aspx#errors. [VE1EUR01FT021.eop-EUR01.prod.protection.outlook.com]</pre>
<p>And indeed, checking the IP status indicated that is was blocked &#8220;because of user complaints or other evidence of spamming&#8221;.</p>
<p>So first I went to the mail logs. Low traffic. No indication that the server has been tricked into sending a lot of mails. No indication that it has been compromised in any way. And when a server has been compromised, you know it.</p>
<p>No chance that there were user complaints, because I got nothing from JMRP. So what the &#8220;evidence of spamming&#8221;?</p>
<p>My best guess: A handful transactional mail messages (at most) to their servers for authenticating email addresses that were marker suspicious by their super software. Putting these messages in quarantine for a few hours is the common solution when that happens. Spam is about volume. If all you got was 4-5 messages, how could that be a spam server? Only if you look at percentage. 100% suspicious. Silly or what?</p>
<p>So I filled in the <a href="http://go.microsoft.com/fwlink/?LinkID=614866" target="_blank">contact support</a> form, and soon enough I got a message saying a ticket has been opened, and 30 minutes later saying</p>
<blockquote><p>We have completed reviewing the IP(s) you submitted. The following table contains the results of our investigation.</p>
<p>Not qualified for mitigation<br />
193.29.56.92<br />
Our investigation has determined that the above IP(s) do not qualify for mitigation. These IP(s) have previously received  mitigations from deliverability support, and have failed to maintain patterns within our guidelines, so they are ineligible for additional mitigation at this time.</p></blockquote>
<p>Cute, heh? And that is followed by a lot of general advice, basically copied from the website, recommending to join JMRP and SDNS. Which I had a year earlier, of course. The script that responded didn&#8217;t even bother to check that.</p>
<p>But it also said:</p>
<blockquote><p>To have Deliverability Support investigate further, please reply to this email with a detailed description of the problem you are having, including specific error messages, and an agent will contact you.</p></blockquote>
<p>And so I did. I wrote that I had joined those two programs a year ago, that the mail volume is low and so on. I doubt it really made a difference. After sending the reply, I got a somewhat automated response rather quickly, now with a more human touch:</p>
<blockquote><p>Hello,</p>
<p>My name is Ayesha and I work with the Outlook.com Deliverability Support Team.</p>
<p>IP: 193.29.56.92</p>
<p>We will be looking into this issue along with the Escalations Team. We understand the urgency of this issue and will provide an update as soon as this is available. Rest assured that this ticket is being tracked and we will get back to you as soon as we have more information to offer.</p>
<p>Thank you for your patience.</p>
<p>Sincerely,<br />
Ayesha</p>
<p>Outlook.com Deliverability Support</p></blockquote>
<p>And then, a few days later, another mail:</p>
<blockquote><p>Hello,</p>
<p>My name is Yaqub and I work with the Outlook.com Deliverability Support Team.</p>
<p>Recent activity coming from your IP(s): ( 193.29.56.92) has been flagged by our system as suspicious, causing your IP to become blocked. I have conducted an investigation into the emails originating from your IP space and have implemented mitigation for your deliverability problem. This process may take 24 &#8211; 48 hours to replicate completely throughout our system.</p>
<p>Please note that lifting the block does not guarantee that your email will be delivered to a user&#8217;s inbox. However, here are some things that can help you with delivery:</p>
<p><em>(and here came the same suggestions on JMRP and SDNS)</em></p></blockquote>
<p>And about 24 hours later, the IP status went back to OK again. And my emails went through normally.</p>
<p>Well, almost. A few days even further down, I attempted to send an email to a live.co.uk destination, and once again, I got the same rejection message (in block list, S3140). The only difference was that the mail server on the other side was hotmail-com.olc.protection.outlook.com (residing in the US), and now eur.olc.protection.outlook.com (somewhere in Europe).</p>
<p>I checked the IP&#8217;s status in SDNS and it was fine. So updating the Europeans on the updated IP status takes a bit time, or what?</p>
<p>So I replied to last email I got from Microsoft&#8217;s support, saying it failed with live.co.uk. I didn&#8217;t get any reply, but a few hours later I tried again, and the mail went through. Coincidence or not.</p>
<p>This time I also caught the related messaged from the mail log. It&#8217;s</p>
<pre>May 01 15:10:28 sm-mta[2239]: 041FASMh002237: to=&lt;xxxxx@live.co.uk&gt;, ctladdr=&lt;eli@billauer.se&gt; (510/500), delay=00:00:00, xdelay=00:00:00, mailer=esmtp, pri=121816, relay=eur.olc.protection.outlook.com. [104.47.1.33], dsn=5.0.0, stat=Service unavailable
May 01 15:10:28 sm-mta[2239]: 041FASMh002237: 041FASMh002239: DSN: Service unavailable</pre>
<p>for a failure, and</p>
<pre>May 02 06:23:00 sm-mta[4024]: 0426Mx1I004021: to=&lt;xxxxx@live.co.uk&gt;, ctladdr=&lt;eli@billauer.se&gt; (510/500), delay=00:00:01, xdelay=00:00:01, mailer=esmtp, pri=121808, relay=eur.olc.protection.outlook.com. [104.47.18.97], dsn=2.0.0, stat=Sent (&lt;5EAD11C3.20105@billauer.se&gt; [InternalId=21887153366859, Hostname=AM6EUR05HT060.eop-eur05.prod.protection.outlook.com] 10627 bytes in 0.246, 42.064 KB/sec Queued mail for delivery -&gt; 250 2.1.5)
</pre>
<p>for success.</p>
<p>Lesson learned: Contact support and insist.</p>
<p>And the lesson to all those using Microsoft&#8217;s mail services: Your provider cuts off your email contacts arbitrarily. Because they are Microsoft.</p>
]]></content:encoded>
			<wfw:commentRss>https://billauer.se/blog/2020/04/microsoft-outlook-hotmail-smtp-spam-blacklist/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Jots on named pipes (FIFOs in Linuxish)</title>
		<link>https://billauer.se/blog/2020/02/software-fifo-named-pipes/</link>
		<comments>https://billauer.se/blog/2020/02/software-fifo-named-pipes/#comments</comments>
		<pubDate>Sat, 29 Feb 2020 10:16:57 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Linux kernel]]></category>
		<category><![CDATA[Microsoft]]></category>

		<guid isPermaLink="false">https://billauer.se/blog/?p=6004</guid>
		<description><![CDATA[Major disclaimer These are pretty random jots that I made while evaluating named pipes as a solution for project. I eventually went for a driver in the kernel for various reasons, so I never got to verify that anything written below is actually correct. I&#8217;ve also written a small post on epoll with named pipes [...]]]></description>
			<content:encoded><![CDATA[<h3>Major disclaimer</h3>
<p>These are pretty random jots that I made while evaluating named pipes as a solution for project. I eventually went for a driver in the kernel for various reasons, so I never got to verify that anything written below is actually correct.</p>
<p>I&#8217;ve also written a <a title="A few epoll jots" href="https://billauer.se/blog/2020/02/epoll-named-pipes-fifo/" target="_blank">small post</a> on epoll with named pipes (in Linux, of course) along with a <a href="https://github.com/billauer/try_epoll" target="_blank">tiny test program</a>.</p>
<h3>Linux named pipes (FIFOs)</h3>
<p>Section 3.162 of IEEE Std 1003.1-2001, Base Definitions, defines FIFO Special File (or FIFO) trivially, and refers to POSIX  IEEE Std 1003.1-2001 for &#8220;Other characteristics&#8221; related to lseek( ), open( ), read( ), and write( ). In section 3.273 it defines Pipe, and says that it &#8220;behaves identically to a FIFO special file&#8221;.</p>
<p>From POSIX IEEE Std 1003.1-2001, System Interfaces, Issue 6, line 27153: &#8220;When opening a FIFO with O_RDONLY or O_WRONLY set: (&#8230;) If O_NONBLOCK is clear, an open( ) for reading-only shall block the calling thread until a thread opens the file for writing. An open( ) for writing-only shall block the calling thread until a thread opens the file for reading.&#8221;</p>
<p>Even though the POSIX standard is available for download at a cost of a few hundred dollars, there&#8217;s the Open Group Base Specification, which matches it quite well: <a href="https://pubs.opengroup.org/onlinepubs/9699919799/" target="_blank">Base Definitions</a> and <a href="https://pubs.opengroup.org/onlinepubs/009695399/functions/contents.html" target="_blank">System Interfaces</a>.</p>
<p><a href="https://brandonwamboldt.ca/how-linux-pipes-work-under-the-hood-1518/" target="_blank">This</a> is a good source on pipes.</p>
<ul>
<li>The buffer for each pipe is 64 kB by default on Linux</li>
<li>An anonymous pipe (created with pipe() ) is just like a named pipe (i.e. a FIFO special file), only that the node is in pipefs, which only the kernel has access to. There are slight differences in how they&#8217;re handled.</li>
</ul>
<p>Reading the source code (fs/pipe.c)</p>
<ul>
<li>This source clearly handles both named and anonymous pipes (the behavior differs slightly).</li>
<li>There&#8217;s F_SETPIPE_SZ and F_GETPIPE_SZ fcntl calls, which clearly allow setting the buffer size. Added in patch 35f3d14dbbc58 from 2010 (v2.6.35).</li>
<li>fifo_open(): The is_pipe boolean is true if the FIFO is a pipe() (has a magic of PIPE_FS). In other words, if it&#8217;s false, it&#8217;s a named pipe.</li>
<li>If a FIFO is opened for read <strong>or </strong>write (not both), the open() call blocks until there&#8217;s a partner, unless O_NONBLOCK is set, in which case the behavior is somewhat messy. The comments imply that this is required by POSIX.</li>
<li>It&#8217;s perfectly fine that a FIFO is opened multiple times both for read and write. Only one reader gets each piece of data, and quite randomly. Writers contribute to the stream independently.</li>
<li>FIFOs and pipes implement the  FIONREAD ioctl() command for telling how many bytes are immediately ready for reading. This is the only ioctl() command implemented however.</li>
<li>The flags returned by epoll_wait() are as understood from pipe_poll(). Not clear what purpose the list of EPOLL* flags in those calls to wake_up_interruptible_sync_poll() has.</li>
</ul>
<p>Things to look at:</p>
<ul>
<li>What if a file descriptor open for read is closed and there&#8217;s no write() blocking on the other side? Is there a way to get a software notification? A zero-length write always succeeds, even if the other side is closed (this case is handled explicitly before the part that produces the EPIPE / SIGPIPE).</li>
<li>Same in the other direction: A descriptor open for write closes, but there&#8217;s no read() to get the EOF. Likewise, a zero-length read() always succeeds, even if the other side is closed (which makes sense, because even if it&#8217;s closed, reading should continue until the end).</li>
<li>Is there a way to wait for the partner without blocking, or must a thread block on it?</li>
<li>What happens on a close() followed immediately by an open()?</li>
<li>What about user opening the file in the wrong direction?</li>
</ul>
<h3>open() with O_NONBLOCK? (not)</h3>
<p>It&#8217;s tempting to open a FIFO with O_NONBLOCK, so there needs not to be a thread blocking while waiting for the other side to be opened. POSIX IEEE Std 1003.1-2001, System Interfaces, Issue 6,says in the part defining open(), page 836:</p>
<p>When opening a FIFO with O_RDONLY or O_WRONLY set:</p>
<ul>
<li>If O_NONBLOCK is set, an open( ) for reading-only shall return without delay. An open( ) for writing-only shall return an error if no process currently has the file open for reading.</li>
<li>If O_NONBLOCK is clear, an open( ) for reading-only shall block the calling thread until a thread opens the file for writing. An open( ) for writing-only shall block the calling thread until a thread opens the file for reading.</li>
</ul>
<p>In the list of error codes for open(), ENXIO is bound (along with another irrelevant sceniario) to: O_NONBLOCK is set, the named file is a FIFO, O_WRONLY is set, and no process has the file open for reading.</p>
<p>Linux&#8217; implementation of FIFOs follows this exactly.</p>
<p>This rules out using O_NONBLOCK for opening a file for write &#8212; it will simply not work. As for opening a file for read, it will work, but the epoll() call won&#8217;t wake up the process before there is data to read. Opening the other side only doesn&#8217;t generate any event.</p>
<h3>Windows named pipes</h3>
<p>The basic reading: <a href="https://docs.microsoft.com/en-us/windows/win32/ipc/pipe-names" target="_blank">Microsoft&#8217;s introduction</a> and <a href="https://docs.microsoft.com/en-us/windows/win32/ipc/pipe-functions" target="_blank">a list of relevant API functions</a>.</p>
<p>General notes:</p>
<ul>
<li>The concept of named pipes in Windows seems to resemble UNIX domain sockets in that it&#8217;s formed with a client / server terminology. Unlike domain sockets, the client may &#8220;connect&#8221; with a plain file open() (actually CreateFile and variants). Hence Windows&#8217; named pipes can be truly full duplex between two processes.</li>
<li>But named pipes can also be accessed remotely. The permissions need to be set explicitly to avoid that.</li>
<li>The client&#8217;s opening of a named pipe is known by the return of  ConnectNamedPipe (or a respective event in OVERLAPPED mode).</li>
<li>Pipe names are <strong>not</strong> case-sensitive.</li>
<li>A pipe is created (by the server) with access mode PIPE_ACCESS_INBOUND, PIPE_ACCESS_OUTBOUND or PIPE_ACCESS_DUPLEX, indicating its direction, as well as the number of instances &#8212; the number of times the pipe can be opened by clients. There&#8217;s PIPE_TYPE_BYTE and PIPE_TYPE_MESSAGE types, the former creating a UNIX-like stream, and the second treats writes to the pipe as atomic messages.</li>
<li>A named pipe ceases to exist when its number of instances goes to zero. It&#8217;s an object, not a file. Hence for a sensible application where a single process generates the named pipe, they vanish when the process terminates.</li>
<li>Use PIPE_WAIT even when non-blocking behavior is required. <strong>Don&#8217;t use</strong> PIPE_NOWAIT flag on creation for achieving non-blocking use of the pipe. Overlapping access is the correct tool. The former is available to <a href="https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipe-type-read-and-wait-modes" target="_blank">allow compatibility with some Microsoft software accident</a>.</li>
<li>If a client needs to connect to a pipe which has all its instances already connected, it may wait for its turn with WaitNamedPipe.</li>
<li>When finishing a connection with a client, FlushFileBuffers() should be called to flush pending written data (if the client didn&#8217;t close the connection first) and then DisconnectNamedPipe().</li>
<li>The suitable mode for working is overlapped I/O. <a href="https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipe-server-using-overlapped-i-o" target="_blank">This is the official example</a>.</li>
<li>There&#8217;s a scary remark on <a href="https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-connectnamedpipe" target="_blank">this page</a> and <a href="https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-disconnectnamedpipe" target="_blank">this</a> claiming that named pipes are effectively useless for IPC, and that the object&#8217;s name has changed, and this is also discussed <a href="https://stackoverflow.com/questions/46497926/named-pipes-no-longer-a-thing-in-windows-10-version-1709" target="_blank">here</a>. It seems however that this remark <a href="https://stackoverflow.com/questions/50650890/named-pipe-in-uwp-app" target="_blank">doesn&#8217;t relate to anything else</a> than <a href="https://docs.microsoft.com/en-us/windows/apps/desktop/choose-your-platform" target="_blank">UWP apps</a>. Or else it wouldn&#8217;t have cause the vulnerability <a href="https://www.exploit-db.com/exploits/44148" target="_blank">mentioned here</a>, and how could Docker use it <a href="https://www.docker.com/blog/docker-windows-server-1709/" target="_blank">this way</a>?</li>
</ul>
<h3>Windows named pipes: Detecting disconnection of client</h3>
<p>The word out there is that a disconnection can&#8217;t be detected unless there&#8217;s an outstanding ReadFile or WriteFile request. This holds true in particular for TCP sockets. So first try this: Make sure  there&#8217;s only one instance, and let the server call WaitNamedPipeA as  soon as a connection is made. This call will hopefully return when the  real client disconnects. This will not work if Windows wants the server  to disconnect as well before considering the pipe instance vacant  enough. It might, because the client is allowed to connect before the  server. It all depends on when Windows decrements the reference count  and cleans up.</p>
]]></content:encoded>
			<wfw:commentRss>https://billauer.se/blog/2020/02/software-fifo-named-pipes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux: Writing a Windows MBR instead of grub</title>
		<link>https://billauer.se/blog/2019/06/windows-grub-mbr/</link>
		<comments>https://billauer.se/blog/2019/06/windows-grub-mbr/#comments</comments>
		<pubDate>Fri, 14 Jun 2019 06:22:31 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Microsoft]]></category>

		<guid isPermaLink="false">https://billauer.se/blog/?p=5755</guid>
		<description><![CDATA[On a test computer, I use /dev/sda1 to contain whatever operating system I need for the moment. At some point, I installed Linux Mint 19.1 properly on that partition, and then I wanted to return to Windows 10. After writing the Windows 10 image to /dev/sda1, I got a message from grub saying it didn&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p>On a test computer, I use /dev/sda1 to contain whatever operating system I need for the moment. At some point, I installed Linux Mint 19.1 properly on that partition, and then I wanted to return to Windows 10. After writing the Windows 10 image to /dev/sda1, I got a message from grub saying it didn&#8217;t detect the filesystem.</p>
<p>Hmmm&#8230; So the MBR was overwritten by GRUB, and now I need to get it back to Windowish. One can use Microsoft&#8217;s rescue disk-on-key, or the quick hack: <a href="https://sourceforge.net/projects/ms-sys/" target="_blank">Download ms-sys</a>, compile with plain &#8220;make&#8221;, don&#8217;t bother to install, and just go from the bin/ directory:</p>
<pre># ./ms-sys -7 /dev/sda</pre>
<p>and Windows 10 boots like a charm.</p>
]]></content:encoded>
			<wfw:commentRss>https://billauer.se/blog/2019/06/windows-grub-mbr/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows 10 is Windows 7 with a new-old skin</title>
		<link>https://billauer.se/blog/2015/11/win10-is-same/</link>
		<comments>https://billauer.se/blog/2015/11/win10-is-same/#comments</comments>
		<pubDate>Wed, 04 Nov 2015 12:08:38 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[Microsoft]]></category>

		<guid isPermaLink="false">https://billauer.se/blog/?p=4842</guid>
		<description><![CDATA[&#8230; with one little difference: It seems like you can install Windows 10 without any product key. According to this post, one can install Windows 10 from scratch, and when prompted for the product key, click &#8220;Skip for now&#8221;. Twice. The installation will have this &#8220;Activate Now&#8221; watermark, and personalization will be off. But otherwise, [...]]]></description>
			<content:encoded><![CDATA[<p>&#8230; with one little difference: It seems like you can install Windows 10 without any product key. According to <a href="http://www.windowscentral.com/you-do-not-need-activate-windows-10" target="_blank">this post</a>, one can install Windows 10 from scratch, and when prompted for the product key, click &#8220;Skip for now&#8221;. Twice. The installation will have this &#8220;Activate Now&#8221; watermark, and personalization will be off. But otherwise, the post says, everything will work fine. Never tried this myself, though.</p>
<p>Either way, it&#8217;s the regular Windows 10 you want to download. Not the N or KN or something.</p>
<p>Wanting to be sure that some driver I&#8217;ve released will work with Windows 10, I upgraded from Windows 7, where the driver was installed, to Windows 10.</p>
<p>To my great surprise, Windows 10 started with the same desktop, including program shortcuts, all running as before. Only a new look and feel, which resembles Windows 8, just slightly less annoying.</p>
<p>I should mention that at the &#8220;Get going fast&#8221; stage of the installation, I went for Customize Settings and turned off basically everything. That&#8217;s where all the &#8220;Send Microsoft X and Y&#8221; goes.</p>
<p>The real surprise was that my own driver was already installed and running on the upgraded Windows 10. If I was looking for a sign that <strong>everything</strong> is the same under the hood, an automatic adoption of already installed driver is a good one. I don&#8217;t think Microsoft would risk doing that unless there was really nothing new.</p>
<p>Needless to say, removing the driver and reinstalling it went as smooth as always. Same device manager, same everything.</p>
<p><strong>IMPORTANT: </strong>For a bare-metal install, boot the USB stick with the ISO image (possibly generated with winusb under Ubuntu) in non-UEFI mode, or the installer refuses to use existing MBR partitions (unless the partition table is GPT anyhow).</p>
<h3>VirtualBox installation notes</h3>
<p>Jots while installing a fresh Windows 10 on VirtualBox <del>v4.3.12</del> under 64-bit Linux. <strong>Correction:</strong> I eventually upgraded to v5.0.12, which lists Windows 10 as a target OS. This was required to make the Windows Addons work.</p>
<ul>
<li>Set OS to Other Windows 32 bit (I suppose other Microsoft selections will work as well)</li>
<li>Under processor, enable PAE/NX</li>
<li>Attempting a 64-bit installation got stuck on the initial Windows splash image, no matter what I tried (maybe this was solved with 5.0.12, didn&#8217;t try this)</li>
<li>Turn off screen saver after installation</li>
<li>The installation will ask for the product key in two different occasions during the installation. Just skip.</li>
<li>Didn&#8217;t work:<br />
<del>In order to install VirtualBox Windows Additions, pick Devices &gt; Insert Guest Additions CD Image&#8230; on the hosts&#8217;s VirtualBox menu. Then start the virtual machine. VirtualBox v4.3.12 doesn&#8217;t support Windows 10, so refuse the automatic run of the CD. Instead, browse the disc&#8217;s content and right-click VBoxWindowsAdditions-x86.exe. Choose Properties. Pick the Compatibility tab, check &#8220;Run this program in compatibility mode&#8221; and pick Windows 8 (as suggested on <a href="http://www.sysprobs.com/install-windows-10-on-virtualbox-and-its-guest-additions" target="_blank">this post</a>). Then run this program, which will then install the drivers properly. Windows will complain that the display adapter doesn&#8217;t work, but that&#8217;s fine. Just reboot.</del></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>https://billauer.se/blog/2015/11/win10-is-same/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Moving a Windows 7-installed hard disk to a new computer</title>
		<link>https://billauer.se/blog/2015/10/microsoft-new-motherboard/</link>
		<comments>https://billauer.se/blog/2015/10/microsoft-new-motherboard/#comments</comments>
		<pubDate>Tue, 20 Oct 2015 09:47:10 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[Microsoft]]></category>

		<guid isPermaLink="false">https://billauer.se/blog/?p=4819</guid>
		<description><![CDATA[This has been documented elsewhere, but it&#8217;s important enough to have a note about here. In short, before switching to a new hardware, it&#8217;s essential to prepare it, or an 0x0000007b blue screen will occur on the new hardware. The trick is to run sysprep.exe (under windows\system32\sysprep\) before the transition. Have &#8220;Generalize&#8221; checked, and choose [...]]]></description>
			<content:encoded><![CDATA[<p>This has been documented <a href="http://www.makeuseof.com/tag/making-sure-windows-7-will-boot-after-changing-the-motherboard/" target="_blank">elsewhere,</a> but it&#8217;s important enough to have a note about here.</p>
<p>In short, <strong>before </strong>switching to a new hardware, it&#8217;s essential to prepare it, or an 0x0000007b blue screen will occur on the new hardware.</p>
<p>The trick is to run sysprep.exe (under windows\system32\sysprep\) before the transition. Have &#8220;Generalize&#8221; checked, and choose &#8220;shutdown&#8221; at the end of the operation (&#8220;Shutdown Options&#8221;).</p>
<p>Once the computer shuts down, move the hard disk to the new computer. Windows should boot smoothly, and start a series of installation stages, including feeding the license key and language settings. Also, an account needs to be created. This account can be deleted afterwards, as the old account is kept. Quite silly, as a matter of fact.</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://billauer.se/blog/2015/10/microsoft-new-motherboard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows 8 recovery notes-to-self</title>
		<link>https://billauer.se/blog/2015/07/windows-8-refresh-pc-media/</link>
		<comments>https://billauer.se/blog/2015/07/windows-8-refresh-pc-media/#comments</comments>
		<pubDate>Wed, 29 Jul 2015 07:19:25 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[Microsoft]]></category>

		<guid isPermaLink="false">https://billauer.se/blog/?p=4730</guid>
		<description><![CDATA[Just some jots as I tried to fix a Windows 8.1 laptop that didn&#8217;t boot (not mine, of course, I can&#8217;t stand Windows 8). It went &#8220;Preparing automatic repair&#8221; immediately on powerup, and then a light blue (not BSOD-blue) screen saying &#8220;Automatic Repair&#8221;, &#8220;Your PC did not start correctly&#8221;. Offering me to Restart or &#8220;Advanced [...]]]></description>
			<content:encoded><![CDATA[<p>Just some jots as I tried to fix a Windows 8.1 laptop that didn&#8217;t boot (not mine, of course, I can&#8217;t stand Windows 8). It went &#8220;Preparing automatic repair&#8221; immediately on powerup, and then a light blue (not BSOD-blue) screen saying &#8220;Automatic Repair&#8221;, &#8220;Your PC did not start correctly&#8221;. Offering me to Restart or &#8220;Advanced Options&#8221;. This is where the saga begins.</p>
<p>Spoiler: Eventually, an accidental attempt brought things back to normal.</p>
<h3>What installation is this?</h3>
<p>I had some trouble telling if the installation was 32 or 64 bit. &#8220;systeminfo&#8221; didn&#8217;t work on command prompt, so I had to guess based upon the existing files. Be sure to look in C: and not in X: (are they the same?).</p>
<p>The ways I could tell it&#8217;s a 64-bit installation:</p>
<ul>
<li>The presence of C:\Program Files (x86)  as well as C:\Program Files (only the latter is present in a 32-bit installation).</li>
<li>The presence of C:\Windows\SysWOW64, which is intended for running 32-bit programs under a 64-bit OS.</li>
</ul>
<p>Note that C:\Windows\System32 is present in both 32- and 64-bit versions.</p>
<h3>Random ideas</h3>
<p>Some things one might want to try out:</p>
<ul>
<li>Run Linux on a LiveUSB stick and run Applications &gt; System Tools &gt; Disk Utility (or similar path) to get some S.M.A.R.T. info from the hard disk.</li>
<li>Run chkdsk /R on Windows&#8217; command prompt to hopefully fix the disk issues</li>
<li><del>Create installation media on Window&#8217;s site (Google for it), as the self-fixing tools ask for it. The exact version of Windows is required for that, so &#8220;systeminfo&#8221; on command prompt should be helpful (if it says X86-based PC it&#8217;s 32 bit Windows, otherwise X64-based PC). In principle, looking at the computer&#8217;s properties is easier, but in recovery mode only command prompt is available.</del></li>
<li>Choose &#8220;Refresh your PC&#8221; under &#8220;Troubleshoot&#8221; in the set of menus that appear when the computer fails to boot properly. The plug in the installation media when requested (don&#8217;t do it beforehand, as it won&#8217;t count). Not that it helped. I got &#8220;The media inserted is not valid. Try again.&#8221; So much for a descriptive error message, after preparing that silly USB stick for an hour or so.</li>
</ul>
<p>So I went for booting the computer from USB, and got the &#8220;The drive where Windows is installed is locked. Unlock the drive and try again&#8221; error when trying to repair the OS. Following <a href="https://www.winhelp.us/repair-your-computer-in-windows-8.html#bootrec" target="_blank">this page</a>, I ran diskpart at command prompt and typed &#8220;list volume&#8221; which indeed printed out the disk partitions. This was done to make sure none appears as &#8220;RAW&#8221;, which would indicate that I don&#8217;t want to touch anything before the disk has been restored to a sane condition.</p>
<p>I also tried</p>
<pre>bootrec /fixmbr
bootrec /fixboot
bootrec /rebuildbcd</pre>
<p>but in vain. There was no difference.</p>
<h3>sfc</h3>
<p>It&#8217;s supposed to be the savior, isn&#8217;t it?</p>
<p>Looking for corrupted system files (System File Checker): &#8220;sfc /scannow&#8221; completed (verification 100% complete) but said that &#8220;Windows Resource Protection could not perform the requested operation&#8221;. The log file was found in X:\WINDOWS\LOGS\CBS\CBS.LOG (note the X:, it was put in the boot volume, not C:) with notepad (don&#8217;t forget to look for &#8220;All Files&#8221; and not just *.txt).</p>
<p>The reason it did nothing was that I didn&#8217;t run it as an Administrator. So going again, as an Administrator, I got “There is a system repair pending which requires reboot to complete. Restart Windows and run sfc again.” So I rebooted, and got the same message again. Very helpful. <a href="https://social.technet.microsoft.com/Forums/windows/en-US/884d38e1-c87c-4549-9d06-7bb0fb929303/force-sfc-to-run-in-windows-7" target="_blank">This page</a> suggests looking what is pending in c:\windows\winsxs\pending.xml, and indeed such file existed. A long XML file, full with info about things that were about to happen.</p>
<p>Following <a href="https://support.4it.com.au/article/how-to-fix-sfc-scannow-there-is-a-system-repair-pending/" target="_blank">this page</a> I went for</p>
<pre>dism.exe /image:C:\ /cleanup-image /revertpendingactions</pre>
<p>which is an extremely annoying utility in that it claims that it doesn&#8217;t recognize the /cleanup-image nor /revertpendingactions options unless the line is typed exactly as above. Did I say something about helpful error messages?</p>
<p>So eventually it finished, and claimed to have done that successfully, but sfc still said there was pending system repair. Rebooting didn&#8217;t help. The pending.xml file was still there.</p>
<p>Trying dism again, it claimed having an error reverting an image, and sending me to a log file. Which, as one would expect, contained tons of rubbish and not much to go with. The reported error was 0x800f082f, which seems to be an undocumented error code. <a href="http://www.varidan.com.au/how-to-fix-the-dreaded-windows-error-0x800f082f/" target="_blank">This post</a> supplied a hack for working it around, but it wasn&#8217;t required in my case &#8212; the problem was the pending.xml file</p>
<p>As it previously complained about not having &#8220;sufficient scratch space&#8221; I  also supplied the /scratchdir:c:\delme option the following time (with  c:\delme being just an empty directory).</p>
<p>At this point I decided to rename pending.xml to was-pending.xml using notepad, which wasn&#8217;t all that simple (Remember to use the C: path, and not the X: default, remember to view all files and not just .txt, and note that changes are not updated in the GUI until I leave the directory and view it again. Things are weird when running in rescue mode). It would make more sense to use some File Manager, but &#8220;explorer&#8221; on command prompt wasn&#8217;t recognized.</p>
<p>sfc claimed not have completed the operation successfully (with a status_not_implemented error in the log). But that didn&#8217;t make any difference either.</p>
<h3>Boot logging</h3>
<p>This <a href="http://windows.microsoft.com/en-us/windows/advanced-startup-options-including-safe-mode#1TC=windows-7" target="_blank">can be triggered off with F8</a> in theory, but probably only when things are relatively OK: Instead, at the Automatic Repair opening screen, go Advanced Options &gt; Troubleshoot &gt; Advanced Options &gt; Startup Settings &gt; Restart. So Windows reboots, but this time with a menu. Pick option 2, Enable boot logging. And boot, which fails again, of course with the same Automatic Repair Screen.</p>
<p>So go Advanced Options &gt; Troubleshoot &gt; Advanced Options &gt; Command Prompt, enter as admin, and open type &#8220;notepad&#8221;.  Well, the file was supposed to be there as C:\windows\ntbtlog.txt, but no such file was there. Microsoft has a rather <a href="https://support.microsoft.com/en-us/kb/275735" target="_blank">useless possible explanation</a>.</p>
<h3>The breakthrough</h3>
<p>Based upon the same menu for enabling Boot logging, I picked (8) &#8220;Disable early-launch anti-malware protection&#8221;. And after a little while, the computer was suddenly up and running!</p>
<p>From a running Windows position, I was offered to run System Restore to a known, recent configurations, and agreed.</p>
<p>The computer started munching and crunching, after which it restarted, and brought me back to the Automatic Repair screen. But now it mentioned a log file on this initial screen: C:\Windows\System32\Logfiles\Srt\SrtTrail.txt. And there it said: Boot critical file C:\Windows\system32\drivers\mfeelamk.sys is corrupt. And also that C:\tbs.sys is corrupt.</p>
<p>So turning off that malware option again, a successful boot was completed again, and again with a message that System Restore had failed.</p>
<p>Indeed there was no C:\tbs.sys file at all, but it was found on C:\Windows\system32\drivers\ with zero lenght. The mfeelamk.sys file turns out to be <a href="https://kc.mcafee.com/corporate/index?page=content&amp;id=KB65784" target="_blank">McAfee&#8217;s anti-malware driver</a>, and let&#8217;s believe that it was problematic indeed. But that explains why turning off early malware check solved the issue.</p>
<p>So I renamed the tbs.sys  so that Windows won&#8217;t find it (requires <a href="http://www.askvg.com/guide-how-to-take-ownership-permission-of-a-file-or-folder-manually-in-windows/" target="_blank">changing ownership and then permissions</a> first) and ran sfc /scannow (from a running system this time, which is much slower). It ended up saying that it found some corrupt files, but was unable to fix some of them.</p>
<p>And then the computer booted up as usual. As simple as that.</p>
<p>So in hindsight, the problem was with one or two driver files which failed to load. Instead of saying that, Windows went &#8220;I&#8217;m sorry, you&#8217;re too stupid to be exposed to that information&#8221; and left me to guessing. And most people don&#8217;t complain. Just reinstall everything. Or even better, buy a new computer.</p>
<h3>Lessons learned</h3>
<ul>
<li>Always run chkdsk /r before trying to mess with the computer</li>
<li>sfc /scannow in rescue mode is worthless</li>
<li>Don&#8217;t try to be clever when fixing a Windows computer. The breakthrough step can&#8217;t be figured out logically on a senseless system. Just try things at random.</li>
<li>Prepare a recovery USB stick, while all is fairly OK</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>https://billauer.se/blog/2015/07/windows-8-refresh-pc-media/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
