Ran into the same test issue on Windows 7, VS2015, OpenSSL 1.0.2l, Net-SSLeay 1.88.
I don't know if what I did is correct, but I was able to get past the compilation issues of the proposed patch and pass all the self tests by:
* including applink.c before XSUB.h (avoids "PerlSIO_f* undeclared" problems)
* replacing the entire first WIN32 block (struct definitions) with "#include <winternl.h>" and replacing the "ImageBaseAddress" references with "Reserved3[1]"
I also used the applink.c from openssl's include directory instead of adding a copy in Net-SSLeay.
Again, I'm not sure if everything is working, but the tests pass.
--- a/Makefile.PL 2020-01-21 14:20:32.000000000 -0500
+++ b/Makefile.PL 2020-01-21 14:20:32.000000000 -0500
@@ -8,7 +8,7 @@
use File::Basename ();
use Symbol qw(gensym);
-# Define this to one if you want to link the openssl libraries statically into
+# Define this to one if you want to link the openssl libraries statically into
# the Net-SSLeay loadable object on Windows
my $win_link_statically = 0;
@@ -76,6 +76,7 @@
},
},
},
+ ($^O eq 'MSWin32' ? (FUNCLIST => ['boot_Net__SSLeay', 'OPENSSL_Applink']) : ()),
ssleay(),
);
--- a/SSLeay.xs 2020-01-21 14:20:32.000000000 -0500
+++ b/SSLeay.xs 2020-01-21 14:20:32.000000000 -0500
@@ -137,6 +137,10 @@
#ifdef __cplusplus
extern "C" {
#endif
+#ifdef WIN32
+/* applink.c needs to be included before XSUB.h to avoid compilation errors */
+#include <openssl/applink.c>
+#endif /* WIN32 */
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
@@ -197,6 +201,10 @@
#endif
#undef BLOCK
+#ifdef WIN32
+#include <winternl.h>
+#endif /* WIN32 */
+
/* Debugging output - to enable use:
*
* perl Makefile.PL DEFINE=-DSHOW_XS_DEBUG
@@ -1766,6 +1774,18 @@
BOOT:
{
+#ifdef WIN32
+/* &__ImageBase is a more efficient way to get "HINSTANCE hinstDLL" arg passed
+ to DllMain of this XS module, or using GetModuleHandleEx() with
+ GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS (<- flag is WinXP or newer only,
+ no Win2k) */
+# ifndef _MSC_VER
+# define __ImageBase _image_base__
+# endif
+ extern IMAGE_DOS_HEADER __ImageBase;
+ PPEB peb;
+ void * OrigBaseAddress;
+#endif
MY_CXT_INIT;
LIB_initialized = 0;
#ifdef USE_ITHREADS
@@ -1787,6 +1807,72 @@
#else
PR1("BOOT:\n");
#endif
+#ifdef WIN32
+ peb = NtCurrentTeb()->ProcessEnvironmentBlock;
+ /* make sure the data under our definition of the PEB is what we want to
+ replace, if the PEB definition is wrong, "peb->ImageBaseAddress"
+ will contain random flags, or random pointers, so then abort patching */
+ if(GetModuleHandle(NULL) != peb->Reserved3[1]) // ImageBaseAddress
+ croak("BOOT: PEB struct definition is wrong");
+ OrigBaseAddress = peb->Reserved3[1]; // ImageBaseAddress
+ /* do the patch */
+ peb->Reserved3[1] = &__ImageBase; // ImageBaseAddress
+ /* verify that the patch had an effect, typically DLLs live at address
+ 0x10000000 unless relocated or rebased, 0x10000000 looks like a flag so
+ the patch location might have been a false positive, and is actually
+ flag 0x10000000 if the PEB definition is wrong/changed in the future by
+ MS, so make sure that patch's effect shows in the public API
+ GetModuleHandle */
+ if(GetModuleHandle(NULL) != (HMODULE)&__ImageBase) {
+ croak("BOOT: PEB patching failed, patch had no effect");
+ }
+ {
+ /* do something that ultimatley calls OPENSSL_Applink to initialize
+ the function pointer now so we can immediatly undo the patch */
+ char fn [MAX_PATH+1];
+ BIO * bio;
+ int bio_flags;
+ FILE * f;
+ /* we know we the XS DLL exist on disk, by the sheer fact that you cant
+ delete a loaded in memory DLL */
+ DWORD res = GetModuleFileName((HMODULE)&__ImageBase, fn, MAX_PATH+1);
+ if (!res || res ==MAX_PATH+1)
+ croak("BOOT: GetModuleFileName failed");
+ f = fopen(fn, "r");
+ /* if BIO_new_file is used, applink wont be called, since openssl will
+ use it's CRT for the rest of the BIO's life, not SSLeay.xs's CRT */
+ bio = BIO_new(BIO_s_file());
+ bio_flags = BIO_get_flags(bio);
+#define PLSSLEAY_FLAGS_UPLINK 0x8000 /* not defined in a public header */
+ /* by default, a new BIO, has BIO_FLAGS_UPLINK flag turned on, atleast
+ for Win32 builds, setting a FILE * may or may not clear that flag.
+ Since the value of BIO_FLAGS_UPLINK may change in the future, detect
+ if it has changed and error out if the flag isn't in a fresh BIO
+ object. We must have BIO_FLAGS_UPLINK turned on to force a call
+ to OPENSSL_Applink */
+ if((bio_flags & PLSSLEAY_FLAGS_UPLINK) != PLSSLEAY_FLAGS_UPLINK)
+ croak("BOOT: this Win32 OpenSSL library isn't using BIO_FLAGS_UPLINK for new BIO objects");
+ /* BIO_set_fp winds up calling BIO_set_fp->file_ctrl, and in file_ctrl
+ in "case BIO_C_SET_FILE_PTR:", openssl does some tests to guess if
+ the FILE * is from openssl's CRT or not, if it guesses it is from
+ openssl's CRT, it then turns off BIO_FLAGS_UPLINK flag, but not all
+ UP_* calls do this guessing, like "case BIO_CTRL_FLUSH:", so for
+ saftey force BIO_FLAGS_UPLINK back on, it may or may not already
+ have been there based on the CRT versions and guessing of origin of
+ the FILE *, this guarentees that an UP_* will be called in BIO_free
+ */
+
+ BIO_set_fp(bio, f, BIO_CLOSE);
+ BIO_set_flags(bio, PLSSLEAY_FLAGS_UPLINK);
+ /* OPENSSL_Applink gets called from inside BIO_free */
+ BIO_free(bio);
+ }
+ /* undo the patch, the static vars inside are now set, if this isn't done
+ VC C debugger and VMMap will both claim SSLeay.dll is "the process" AKA
+ "the .exe that started the process" which is very confusing to someone
+ who is using these diagnostic tools */
+ peb->Reserved3[1] = OrigBaseAddress; // ImageBaseAddress
+#endif
}
void