This won't be possible without the functionality of the :blank pseudo-class, I'm afraid.1
There are only two possible places you can insert a ::before pseudo-element in your scenario: in the ul, or in a li. Since you want to insert the generated content only when no li elements are present, that leaves you only with ul.
Although ::before and ::after are inserted before and after an element's descendant elements respectively, you can't target them relative to those descendant elements with a sibling combinator, and pseudo-elements currently do not support structural pseudo-classes. Which means, in other words, you won't be able to say "prevent ul::before from generating content in the presence of one or more li elements", nor can you apply the :only-child pseudo-class to ul::before.
In a situation where one can use :empty, it's as simple as
ul:empty::before { content: 'abc'; }
but since you cannot use :empty for the reasons you have given, if you really cannot prevent the whitespace from being generated (e.g. if the content is coming from a WYSIWYG editor or some other transformation that may result in leftover whitespace) you'll have to add a class to any ul elements with no children.
1 A recent revision to selectors-4 proposes subsuming the functionality of :blank into :empty instead, but that likewise is new and requires the cooperation of implementers.